@stevenvo780/st-lang 2.0.4 → 2.5.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/dist/cli/index.js.map +1 -1
- package/dist/lexer/tokens.d.ts.map +1 -1
- package/dist/parser/parser.d.ts +1 -0
- package/dist/parser/parser.d.ts.map +1 -1
- package/dist/parser/parser.js +99 -22
- package/dist/parser/parser.js.map +1 -1
- package/dist/profiles/aristotelian/syllogistic.d.ts.map +1 -1
- package/dist/profiles/aristotelian/syllogistic.js +219 -15
- package/dist/profiles/aristotelian/syllogistic.js.map +1 -1
- package/dist/profiles/arithmetic/index.d.ts +1 -6
- package/dist/profiles/arithmetic/index.d.ts.map +1 -1
- package/dist/profiles/arithmetic/index.js +142 -65
- package/dist/profiles/arithmetic/index.js.map +1 -1
- package/dist/profiles/classical/first-order.d.ts +2 -0
- package/dist/profiles/classical/first-order.d.ts.map +1 -1
- package/dist/profiles/classical/first-order.js +375 -51
- package/dist/profiles/classical/first-order.js.map +1 -1
- package/dist/profiles/classical/propositional.d.ts +7 -0
- package/dist/profiles/classical/propositional.d.ts.map +1 -1
- package/dist/profiles/classical/propositional.js +467 -32
- package/dist/profiles/classical/propositional.js.map +1 -1
- package/dist/profiles/deontic/standard.d.ts.map +1 -1
- package/dist/profiles/deontic/standard.js +13 -1
- package/dist/profiles/deontic/standard.js.map +1 -1
- package/dist/profiles/epistemic/s5.d.ts.map +1 -1
- package/dist/profiles/epistemic/s5.js +14 -1
- package/dist/profiles/epistemic/s5.js.map +1 -1
- package/dist/profiles/intuitionistic/propositional.d.ts.map +1 -1
- package/dist/profiles/intuitionistic/propositional.js +98 -13
- package/dist/profiles/intuitionistic/propositional.js.map +1 -1
- package/dist/profiles/modal/k.d.ts.map +1 -1
- package/dist/profiles/modal/k.js +9 -1
- package/dist/profiles/modal/k.js.map +1 -1
- package/dist/profiles/paraconsistent/belnap.d.ts +2 -1
- package/dist/profiles/paraconsistent/belnap.d.ts.map +1 -1
- package/dist/profiles/paraconsistent/belnap.js +81 -4
- package/dist/profiles/paraconsistent/belnap.js.map +1 -1
- package/dist/profiles/probabilistic/basic.d.ts.map +1 -1
- package/dist/profiles/probabilistic/basic.js +71 -1
- package/dist/profiles/probabilistic/basic.js.map +1 -1
- package/dist/profiles/shared/base-profile.d.ts +4 -2
- package/dist/profiles/shared/base-profile.d.ts.map +1 -1
- package/dist/profiles/shared/base-profile.js +72 -11
- package/dist/profiles/shared/base-profile.js.map +1 -1
- package/dist/profiles/shared/tableau-engine.d.ts +7 -7
- package/dist/profiles/shared/tableau-engine.d.ts.map +1 -1
- package/dist/profiles/shared/tableau-engine.js +74 -70
- package/dist/profiles/shared/tableau-engine.js.map +1 -1
- package/dist/profiles/temporal/ltl.d.ts +1 -0
- package/dist/profiles/temporal/ltl.d.ts.map +1 -1
- package/dist/profiles/temporal/ltl.js +65 -0
- package/dist/profiles/temporal/ltl.js.map +1 -1
- package/dist/protocol/handler.d.ts.map +1 -1
- package/dist/protocol/handler.js +96 -27
- package/dist/protocol/handler.js.map +1 -1
- package/dist/runtime/cross-system-compare.d.ts +4 -0
- package/dist/runtime/cross-system-compare.d.ts.map +1 -0
- package/dist/runtime/cross-system-compare.js +50 -0
- package/dist/runtime/cross-system-compare.js.map +1 -0
- package/dist/runtime/fallacies.d.ts.map +1 -1
- package/dist/runtime/fallacies.js +130 -0
- package/dist/runtime/fallacies.js.map +1 -1
- package/dist/runtime/format.d.ts +5 -0
- package/dist/runtime/format.d.ts.map +1 -1
- package/dist/runtime/format.js +54 -6
- package/dist/runtime/format.js.map +1 -1
- package/dist/runtime/formula-classifier.d.ts +18 -0
- package/dist/runtime/formula-classifier.d.ts.map +1 -0
- package/dist/runtime/formula-classifier.js +183 -0
- package/dist/runtime/formula-classifier.js.map +1 -0
- package/dist/runtime/interpreter.d.ts +1 -0
- package/dist/runtime/interpreter.d.ts.map +1 -1
- package/dist/runtime/interpreter.js +221 -49
- package/dist/runtime/interpreter.js.map +1 -1
- package/dist/runtime/known-theorems.d.ts +12 -0
- package/dist/runtime/known-theorems.d.ts.map +1 -0
- package/dist/runtime/known-theorems.js +147 -0
- package/dist/runtime/known-theorems.js.map +1 -0
- package/dist/tests/arithmetic.test.js +81 -27
- package/dist/tests/arithmetic.test.js.map +1 -1
- package/dist/tests/core.test.js +2 -2
- package/dist/tests/core.test.js.map +1 -1
- package/dist/tests/engines.test.js +1 -1
- package/dist/tests/engines.test.js.map +1 -1
- package/dist/tests/examples.test.js +1 -7
- package/dist/tests/examples.test.js.map +1 -1
- package/dist/tests/exhaustive-matrix.test.js +2 -2
- package/dist/tests/philosophy.test.js +2 -0
- package/dist/tests/philosophy.test.js.map +1 -1
- package/dist/tests/profiles.test.js +111 -0
- package/dist/tests/profiles.test.js.map +1 -1
- package/dist/tests/stress-exhaustive.test.js +94 -29
- package/dist/tests/stress-exhaustive.test.js.map +1 -1
- package/dist/tests/v1-features.test.js +10 -4
- package/dist/tests/v1-features.test.js.map +1 -1
- package/dist/types/index.d.ts +29 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -12,6 +12,7 @@ const fallacies_1 = require("./fallacies");
|
|
|
12
12
|
// Barrel import: registra todos los perfiles automáticamente
|
|
13
13
|
require("../profiles");
|
|
14
14
|
const compiler_1 = require("../text-layer/compiler");
|
|
15
|
+
const formula_classifier_1 = require("./formula-classifier");
|
|
15
16
|
class Interpreter {
|
|
16
17
|
theory;
|
|
17
18
|
profile = null;
|
|
@@ -53,7 +54,7 @@ class Interpreter {
|
|
|
53
54
|
name,
|
|
54
55
|
params: ['arg'],
|
|
55
56
|
body: [],
|
|
56
|
-
source: { line: 0, column: 0 }
|
|
57
|
+
source: { line: 0, column: 0 },
|
|
57
58
|
});
|
|
58
59
|
}
|
|
59
60
|
}
|
|
@@ -315,7 +316,8 @@ class Interpreter {
|
|
|
315
316
|
const actualInstanceName = resolvedPrefix.name;
|
|
316
317
|
const scope = this.theories.get(actualInstanceName);
|
|
317
318
|
if (scope) {
|
|
318
|
-
if (scope.privateMembers.has(memberName) &&
|
|
319
|
+
if (scope.privateMembers.has(memberName) &&
|
|
320
|
+
this.currentTheoryName !== actualInstanceName)
|
|
319
321
|
return f;
|
|
320
322
|
if (scope.letBindings.has(memberName))
|
|
321
323
|
return this.resolveFormula(scope.letBindings.get(memberName), new Set(visited));
|
|
@@ -369,8 +371,9 @@ class Interpreter {
|
|
|
369
371
|
}
|
|
370
372
|
// Recorrer hijos recursivamente
|
|
371
373
|
if (f.args && f.args.length > 0) {
|
|
372
|
-
const newArgs = f.args.map(a => a ? this.resolveFormula(a, new Set(visited)) : a);
|
|
373
|
-
const
|
|
374
|
+
const newArgs = f.args.map((a) => (a ? this.resolveFormula(a, new Set(visited)) : a));
|
|
375
|
+
const oldArgs = f.args;
|
|
376
|
+
const changed = newArgs.some((a, i) => a !== oldArgs[i]);
|
|
374
377
|
if (changed) {
|
|
375
378
|
return { ...f, args: newArgs };
|
|
376
379
|
}
|
|
@@ -583,7 +586,7 @@ class Interpreter {
|
|
|
583
586
|
}
|
|
584
587
|
execAnalyzeCmd(stmt) {
|
|
585
588
|
const profile = this.requireProfile();
|
|
586
|
-
const premises = stmt.premises.map(p => this.resolveFormula(p));
|
|
589
|
+
const premises = stmt.premises.map((p) => this.resolveFormula(p));
|
|
587
590
|
const conclusion = this.resolveFormula(stmt.conclusion);
|
|
588
591
|
const fallacies = (0, fallacies_1.detectFallacies)(premises, conclusion, profile);
|
|
589
592
|
const pStr = premises.map((p) => (0, format_1.formulaToUnicode)(p)).join(', ');
|
|
@@ -705,7 +708,6 @@ class Interpreter {
|
|
|
705
708
|
/** Crea una instancia de una teoría y la registra en this.theories */
|
|
706
709
|
instantiateTheory(node, instanceName, args = []) {
|
|
707
710
|
const theoryName = instanceName || node.name;
|
|
708
|
-
const templateName = node.name;
|
|
709
711
|
// Crear scope vacío
|
|
710
712
|
const scope = {
|
|
711
713
|
name: theoryName,
|
|
@@ -832,19 +834,19 @@ class Interpreter {
|
|
|
832
834
|
const profile = this.requireProfile();
|
|
833
835
|
for (const branch of stmt.branches) {
|
|
834
836
|
const resolved = this.resolveFormula(branch.formula);
|
|
835
|
-
let matched
|
|
837
|
+
let matched;
|
|
836
838
|
if (branch.condition === 'valid' || branch.condition === 'invalid') {
|
|
837
839
|
const result = profile.checkValid(resolved);
|
|
838
|
-
matched =
|
|
839
|
-
? result.status === 'valid'
|
|
840
|
-
: result.status !== 'valid';
|
|
840
|
+
matched =
|
|
841
|
+
branch.condition === 'valid' ? result.status === 'valid' : result.status !== 'valid';
|
|
841
842
|
}
|
|
842
843
|
else {
|
|
843
844
|
// satisfiable / unsatisfiable
|
|
844
845
|
const result = profile.checkSatisfiable(resolved);
|
|
845
|
-
matched =
|
|
846
|
-
|
|
847
|
-
|
|
846
|
+
matched =
|
|
847
|
+
branch.condition === 'satisfiable'
|
|
848
|
+
? result.status === 'satisfiable' || result.status === 'valid'
|
|
849
|
+
: result.status === 'unsatisfiable';
|
|
848
850
|
}
|
|
849
851
|
if (matched) {
|
|
850
852
|
for (const bodyStmt of branch.body) {
|
|
@@ -894,18 +896,18 @@ class Interpreter {
|
|
|
894
896
|
break;
|
|
895
897
|
iter++;
|
|
896
898
|
const resolved = this.resolveFormula(stmt.formula);
|
|
897
|
-
let matched
|
|
899
|
+
let matched;
|
|
898
900
|
if (stmt.condition === 'valid' || stmt.condition === 'invalid') {
|
|
899
901
|
const result = profile.checkValid(resolved);
|
|
900
|
-
matched =
|
|
901
|
-
? result.status === 'valid'
|
|
902
|
-
: result.status !== 'valid';
|
|
902
|
+
matched =
|
|
903
|
+
stmt.condition === 'valid' ? result.status === 'valid' : result.status !== 'valid';
|
|
903
904
|
}
|
|
904
905
|
else {
|
|
905
906
|
const result = profile.checkSatisfiable(resolved);
|
|
906
|
-
matched =
|
|
907
|
-
|
|
908
|
-
|
|
907
|
+
matched =
|
|
908
|
+
stmt.condition === 'satisfiable'
|
|
909
|
+
? result.status === 'satisfiable' || result.status === 'valid'
|
|
910
|
+
: result.status === 'unsatisfiable';
|
|
909
911
|
}
|
|
910
912
|
if (!matched)
|
|
911
913
|
break;
|
|
@@ -962,8 +964,8 @@ class Interpreter {
|
|
|
962
964
|
}
|
|
963
965
|
const scope = this.theories.get(actualInstanceName);
|
|
964
966
|
if (scope) {
|
|
965
|
-
// En ST actual, las funciones no se guardan en TheoryScope sino que se ejecutan
|
|
966
|
-
// en el contexto del intérprete. Para soportar métodos de instancia,
|
|
967
|
+
// En ST actual, las funciones no se guardan en TheoryScope sino que se ejecutan
|
|
968
|
+
// en el contexto del intérprete. Para soportar métodos de instancia,
|
|
967
969
|
// necesitamos que las funciones estén vinculadas al scope o prefijadas.
|
|
968
970
|
// Como solución rápida y potente: buscamos la función prefijada en el mapa global.
|
|
969
971
|
const internalFnName = `${actualInstanceName}.${methodName}`;
|
|
@@ -1088,7 +1090,7 @@ class Interpreter {
|
|
|
1088
1090
|
const isTrue = result.status === 'valid' || result.status === 'satisfiable';
|
|
1089
1091
|
return { kind: 'atom', name: `"${isTrue ? 'True' : 'False'}"`, source: arg.source };
|
|
1090
1092
|
}
|
|
1091
|
-
catch
|
|
1093
|
+
catch {
|
|
1092
1094
|
return { kind: 'atom', name: '"Error"', source: arg.source };
|
|
1093
1095
|
}
|
|
1094
1096
|
}
|
|
@@ -1097,17 +1099,21 @@ class Interpreter {
|
|
|
1097
1099
|
return { kind: 'atom', name: `"{ ${atoms.join(', ')} }"`, source: arg.source };
|
|
1098
1100
|
}
|
|
1099
1101
|
if (name === 'input') {
|
|
1100
|
-
const prompt = arg.kind === 'atom' && arg.name?.startsWith('"')
|
|
1101
|
-
|
|
1102
|
+
const prompt = arg.kind === 'atom' && arg.name?.startsWith('"')
|
|
1103
|
+
? arg.name.replace(/(^"|"$)/g, '')
|
|
1104
|
+
: (0, propositional_1.formulaToString)(arg);
|
|
1105
|
+
let inputStr;
|
|
1102
1106
|
try {
|
|
1103
1107
|
process.stdout.write(prompt + ' ');
|
|
1108
|
+
/* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-argument */
|
|
1104
1109
|
const fs = require('fs');
|
|
1105
1110
|
const buf = Buffer.alloc(256);
|
|
1106
1111
|
const bytesRead = fs.readSync(process.stdin.fd, buf, 0, 256, null);
|
|
1107
1112
|
inputStr = buf.toString('utf8', 0, bytesRead).trim();
|
|
1113
|
+
/* eslint-enable @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-argument */
|
|
1108
1114
|
}
|
|
1109
|
-
catch
|
|
1110
|
-
inputStr =
|
|
1115
|
+
catch {
|
|
1116
|
+
inputStr = 'interactive_not_supported';
|
|
1111
1117
|
}
|
|
1112
1118
|
return { kind: 'atom', name: `"${inputStr}"`, source: arg.source };
|
|
1113
1119
|
}
|
|
@@ -1127,7 +1133,7 @@ class Interpreter {
|
|
|
1127
1133
|
// Intentar leer el archivo (solo funciona en Node.js / CLI)
|
|
1128
1134
|
let source;
|
|
1129
1135
|
try {
|
|
1130
|
-
|
|
1136
|
+
/* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */
|
|
1131
1137
|
const fs = require('fs');
|
|
1132
1138
|
const path = require('path');
|
|
1133
1139
|
// Resolver relativo al archivo actual si no es absoluto
|
|
@@ -1135,6 +1141,7 @@ class Interpreter {
|
|
|
1135
1141
|
? filePath
|
|
1136
1142
|
: path.resolve(path.dirname(stmt.source.file || '.'), filePath);
|
|
1137
1143
|
source = fs.readFileSync(resolved, 'utf-8');
|
|
1144
|
+
/* eslint-enable @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */
|
|
1138
1145
|
}
|
|
1139
1146
|
catch {
|
|
1140
1147
|
throw new Error(`No se pudo importar '${filePath}': archivo no encontrado`);
|
|
@@ -1220,30 +1227,146 @@ class Interpreter {
|
|
|
1220
1227
|
emit(msg) {
|
|
1221
1228
|
this.stdoutLines.push(msg);
|
|
1222
1229
|
}
|
|
1230
|
+
getVerbosity() {
|
|
1231
|
+
const v = this.letBindings.get('verbose');
|
|
1232
|
+
if (v && v.kind === 'atom' && v.name) {
|
|
1233
|
+
const n = v.name.toLowerCase();
|
|
1234
|
+
// Remove quotes if present
|
|
1235
|
+
return n.replace(/(^"|"$)/g, '');
|
|
1236
|
+
}
|
|
1237
|
+
return 'off';
|
|
1238
|
+
}
|
|
1223
1239
|
emitResult(cmd, result) {
|
|
1224
1240
|
const statusIcon = this.statusIcon(result.status);
|
|
1225
1241
|
this.emit(`${statusIcon} [${cmd}] ${result.output || result.status}`);
|
|
1242
|
+
const verbosity = this.getVerbosity();
|
|
1243
|
+
if (result.educationalNote && verbosity === 'on') {
|
|
1244
|
+
this.emit(` Nota pedagógica: ${result.educationalNote}`);
|
|
1245
|
+
}
|
|
1246
|
+
if (result.paradoxWarning) {
|
|
1247
|
+
this.emit(` ⚠ PARADOJA: ${result.paradoxWarning}`);
|
|
1248
|
+
}
|
|
1249
|
+
// Clasificación de la fórmula (si tenemos verbosidad on o si está precalculado)
|
|
1250
|
+
if (result.formula && (verbosity === 'on' || result.formulaClassification)) {
|
|
1251
|
+
const cls = (0, formula_classifier_1.classifyFormula)(result.formula);
|
|
1252
|
+
const name = result.formulaClassification || cls.formulaClassification;
|
|
1253
|
+
if (name) {
|
|
1254
|
+
this.emit(` Identificación: ${name}`);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
if (result.reasoningType) {
|
|
1258
|
+
this.emit(` Patrón de razonamiento: ${result.reasoningType}`);
|
|
1259
|
+
}
|
|
1260
|
+
if (result.reasoningSchema) {
|
|
1261
|
+
this.emit(` Esquema: ${result.reasoningSchema}`);
|
|
1262
|
+
}
|
|
1263
|
+
if (result.normalForms && verbosity === 'on') {
|
|
1264
|
+
this.emit(` Formas Normales:`);
|
|
1265
|
+
if (result.normalForms.nnf)
|
|
1266
|
+
this.emit(` NNF: ${result.normalForms.nnf}`);
|
|
1267
|
+
if (result.normalForms.cnf)
|
|
1268
|
+
this.emit(` CNF: ${result.normalForms.cnf}`);
|
|
1269
|
+
if (result.normalForms.dnf)
|
|
1270
|
+
this.emit(` DNF: ${result.normalForms.dnf}`);
|
|
1271
|
+
if (result.normalForms.pnf)
|
|
1272
|
+
this.emit(` PNF: ${result.normalForms.pnf}`);
|
|
1273
|
+
if (result.normalForms.skolem)
|
|
1274
|
+
this.emit(` Skolem: ${result.normalForms.skolem}`);
|
|
1275
|
+
}
|
|
1276
|
+
if (result.formula && (verbosity === 'on' || cmd === 'explain')) {
|
|
1277
|
+
/* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call */
|
|
1278
|
+
const { compareAcrossSystems } = require('./cross-system-compare');
|
|
1279
|
+
const { registry } = require('../profiles/interface');
|
|
1280
|
+
const comp = result.crossSystemComparison || compareAcrossSystems(result.formula, registry);
|
|
1281
|
+
/* eslint-enable @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call */
|
|
1282
|
+
if (Object.keys(comp).length > 0) {
|
|
1283
|
+
this.emit(` Comparación entre sistemas:`);
|
|
1284
|
+
for (const [sys, val] of Object.entries(comp)) {
|
|
1285
|
+
this.emit(` ${sys.padEnd(30)} ${val}`);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
const outputFormatRaw = this.letBindings.get('output');
|
|
1290
|
+
const isLatex = outputFormatRaw?.kind === 'atom' &&
|
|
1291
|
+
outputFormatRaw.name?.replace(/['"]/g, '').toLowerCase() === 'latex';
|
|
1226
1292
|
const proof = result.proof;
|
|
1227
|
-
if (proof &&
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1293
|
+
if (proof &&
|
|
1294
|
+
proof.steps.length > 0 &&
|
|
1295
|
+
(verbosity === 'on' || verbosity === 'proof' || cmd === 'derive' || cmd === 'prove')) {
|
|
1296
|
+
if (isLatex) {
|
|
1297
|
+
/* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call */
|
|
1298
|
+
const { proofToLaTeX } = require('./format');
|
|
1299
|
+
this.emit(' Prueba (LaTeX):');
|
|
1300
|
+
this.emit(proofToLaTeX(proof));
|
|
1301
|
+
/* eslint-enable @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call */
|
|
1302
|
+
}
|
|
1303
|
+
else {
|
|
1304
|
+
this.emit(' Prueba:');
|
|
1305
|
+
for (const step of proof.steps) {
|
|
1306
|
+
const premisesStr = step.premises.length > 0 ? ` [de ${step.premises.join(', ')}]` : '';
|
|
1307
|
+
this.emit(` ${step.stepNumber}. ${(0, format_1.formulaToUnicode)(step.formula)} — ${step.justification}${premisesStr}`);
|
|
1308
|
+
}
|
|
1232
1309
|
}
|
|
1233
1310
|
}
|
|
1234
1311
|
const model = result.model;
|
|
1235
|
-
if (model &&
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1312
|
+
if (model &&
|
|
1313
|
+
(verbosity === 'on' ||
|
|
1314
|
+
verbosity === 'model' ||
|
|
1315
|
+
cmd === 'countermodel' ||
|
|
1316
|
+
cmd === 'check_valid' ||
|
|
1317
|
+
cmd === 'check_satisfiable')) {
|
|
1318
|
+
// Display Kripke model with worlds if available
|
|
1319
|
+
if (model.worlds && model.worlds.length > 0) {
|
|
1320
|
+
this.emit(' Contramodelo Kripke:');
|
|
1321
|
+
this.emit(` Mundos: {${model.worlds.map((w) => w.name).join(', ')}}`);
|
|
1322
|
+
this.emit(' Accesibilidad:');
|
|
1323
|
+
for (const w of model.worlds) {
|
|
1324
|
+
if (w.accessible.length > 0) {
|
|
1325
|
+
this.emit(` ${w.name} R ${w.accessible.join(', ')}`);
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
this.emit(' Valuación:');
|
|
1329
|
+
for (const w of model.worlds) {
|
|
1330
|
+
const trueAtoms = Object.entries(w.valuation)
|
|
1331
|
+
.filter(([, val]) => val)
|
|
1332
|
+
.map(([k]) => k);
|
|
1333
|
+
const falseAtoms = Object.entries(w.valuation)
|
|
1334
|
+
.filter(([, val]) => !val)
|
|
1335
|
+
.map(([k]) => k);
|
|
1336
|
+
const parts = [];
|
|
1337
|
+
if (trueAtoms.length > 0)
|
|
1338
|
+
parts.push(trueAtoms.join(', '));
|
|
1339
|
+
if (falseAtoms.length > 0)
|
|
1340
|
+
parts.push(`¬${falseAtoms.join(', ¬')}`);
|
|
1341
|
+
this.emit(` V(${w.name}) = {${parts.join(', ')}}`);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
else if (model.valuation) {
|
|
1345
|
+
// Flat propositional model
|
|
1346
|
+
this.emit(' Modelo / Valuación:');
|
|
1347
|
+
for (const [k, v] of Object.entries(model.valuation)) {
|
|
1348
|
+
const desc = this.letDescriptions.get(k);
|
|
1349
|
+
const descStr = desc ? ` ("${desc}")` : '';
|
|
1350
|
+
this.emit(` ${k}${descStr} = ${String(v)}`);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
if (result.tableauTrace &&
|
|
1355
|
+
result.tableauTrace.length > 0 &&
|
|
1356
|
+
(verbosity === 'on' ||
|
|
1357
|
+
verbosity === 'proof' ||
|
|
1358
|
+
cmd === 'check_valid' ||
|
|
1359
|
+
cmd === 'check_satisfiable')) {
|
|
1360
|
+
this.emit(' Traza del tableau:');
|
|
1361
|
+
for (let i = 0; i < result.tableauTrace.length; i++) {
|
|
1362
|
+
const step = result.tableauTrace[i];
|
|
1363
|
+
this.emit(` ${i + 1}. ${step.toString ? step.toString() : String(step)}`);
|
|
1241
1364
|
}
|
|
1242
1365
|
}
|
|
1243
1366
|
// Mostrar leyenda de variables con descripción si hay alguna relevante
|
|
1244
1367
|
if (this.letDescriptions.size > 0 && result.formula) {
|
|
1245
1368
|
const atoms = this.collectAtoms(result.formula);
|
|
1246
|
-
const relevantDescs = atoms.filter(a => this.letDescriptions.has(a));
|
|
1369
|
+
const relevantDescs = atoms.filter((a) => this.letDescriptions.has(a));
|
|
1247
1370
|
if (relevantDescs.length > 0) {
|
|
1248
1371
|
this.emit(' Donde:');
|
|
1249
1372
|
for (const a of relevantDescs) {
|
|
@@ -1291,23 +1414,72 @@ class Interpreter {
|
|
|
1291
1414
|
}
|
|
1292
1415
|
}
|
|
1293
1416
|
formatTruthTable(formula, tt) {
|
|
1417
|
+
const verbosity = this.getVerbosity();
|
|
1418
|
+
const isVerbose = verbosity === 'on' || verbosity === 'model';
|
|
1294
1419
|
const lines = [];
|
|
1295
|
-
|
|
1296
|
-
const
|
|
1420
|
+
// Detect Belnap (4-valued) table: results are strings like 'T','F','B','N'
|
|
1421
|
+
const isBelnap = tt.rows.length > 0 && typeof tt.rows[0].result === 'string'
|
|
1422
|
+
&& ['T', 'F', 'B', 'N'].includes(String(tt.rows[0].result));
|
|
1423
|
+
if (isBelnap) {
|
|
1424
|
+
lines.push(`Tabla de verdad Belnap (4 valores) para: ${(0, propositional_1.formulaToString)(formula)}`);
|
|
1425
|
+
lines.push('');
|
|
1426
|
+
}
|
|
1297
1427
|
// Header
|
|
1298
|
-
|
|
1428
|
+
const colLabels = [...tt.variables];
|
|
1429
|
+
if (isVerbose && tt.subFormulas) {
|
|
1430
|
+
tt.subFormulas.forEach((sf) => colLabels.push(sf.label));
|
|
1431
|
+
}
|
|
1432
|
+
colLabels.push((0, propositional_1.formulaToString)(formula));
|
|
1433
|
+
const colWidths = colLabels.map((h) => Math.max(h.length, 5));
|
|
1434
|
+
lines.push(colLabels.map((h, i) => h.padEnd(colWidths[i])).join(' | '));
|
|
1299
1435
|
lines.push(colWidths.map((w) => '-'.repeat(w)).join('-+-'));
|
|
1300
1436
|
// Rows
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1437
|
+
const designated = new Set(['T', 'B']);
|
|
1438
|
+
for (let rowIndex = 0; rowIndex < tt.rows.length; rowIndex++) {
|
|
1439
|
+
const row = tt.rows[rowIndex];
|
|
1440
|
+
const vals = tt.variables.map((v) => {
|
|
1441
|
+
const val = row.valuation[v];
|
|
1442
|
+
if (typeof val === 'string')
|
|
1443
|
+
return val;
|
|
1444
|
+
return val ? 'T' : 'F';
|
|
1445
|
+
});
|
|
1446
|
+
if (isVerbose && tt.subFormulas && tt.subFormulaValues) {
|
|
1447
|
+
const subVals = tt.subFormulaValues[rowIndex];
|
|
1448
|
+
tt.subFormulas.forEach((sf) => {
|
|
1449
|
+
let v = subVals[sf.label];
|
|
1450
|
+
if (typeof v === 'boolean')
|
|
1451
|
+
v = v ? 'T' : 'F';
|
|
1452
|
+
vals.push(String(v));
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1455
|
+
let finalVal = row.result;
|
|
1456
|
+
if (typeof finalVal === 'boolean')
|
|
1457
|
+
finalVal = finalVal ? 'T' : 'F';
|
|
1458
|
+
vals.push(String(finalVal));
|
|
1459
|
+
const isCountermodel = (tt.isTautology === false && !row.result) || (tt.isSatisfiable && row.result);
|
|
1460
|
+
const rowStr = vals.map((v, i) => v.padEnd(colWidths[i])).join(' | ');
|
|
1461
|
+
// Belnap designation marker
|
|
1462
|
+
if (isBelnap && designated.has(String(finalVal))) {
|
|
1463
|
+
lines.push(`${rowStr} ⊛ Designado`);
|
|
1464
|
+
}
|
|
1465
|
+
else if (isVerbose && isCountermodel) {
|
|
1466
|
+
lines.push(`${rowStr} ←`);
|
|
1467
|
+
}
|
|
1468
|
+
else {
|
|
1469
|
+
lines.push(rowStr);
|
|
1470
|
+
}
|
|
1305
1471
|
}
|
|
1306
1472
|
lines.push('');
|
|
1473
|
+
if (tt.satisfyingCount !== undefined && tt.totalCount !== undefined) {
|
|
1474
|
+
lines.push(`${tt.satisfyingCount}/${tt.totalCount} valuaciones verdaderas`);
|
|
1475
|
+
}
|
|
1476
|
+
if (isBelnap) {
|
|
1477
|
+
lines.push('Valores designados (portadores de verdad): {T, B}');
|
|
1478
|
+
}
|
|
1307
1479
|
if (tt.isTautology)
|
|
1308
|
-
lines.push('→ Tautologia');
|
|
1480
|
+
lines.push('→ Tautologia ✓');
|
|
1309
1481
|
else if (tt.isContradiction)
|
|
1310
|
-
lines.push('→ Contradiccion');
|
|
1482
|
+
lines.push('→ Contradiccion ✗');
|
|
1311
1483
|
else
|
|
1312
1484
|
lines.push('→ Contingente (satisfacible)');
|
|
1313
1485
|
return lines.join('\n');
|