@stevenvo780/st-lang 3.0.1 → 3.1.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/parser/parser.d.ts.map +1 -1
- package/dist/parser/parser.js +6 -3
- package/dist/parser/parser.js.map +1 -1
- package/dist/profiles/classical/first-order.d.ts +1 -1
- package/dist/profiles/classical/first-order.d.ts.map +1 -1
- package/dist/profiles/classical/first-order.js +50 -8
- package/dist/profiles/classical/first-order.js.map +1 -1
- package/dist/profiles/classical/propositional.d.ts.map +1 -1
- package/dist/profiles/classical/propositional.js +380 -32
- package/dist/profiles/classical/propositional.js.map +1 -1
- package/dist/profiles/paraconsistent/belnap.d.ts.map +1 -1
- package/dist/profiles/paraconsistent/belnap.js +24 -4
- package/dist/profiles/paraconsistent/belnap.js.map +1 -1
- package/dist/runtime/interpreter.d.ts.map +1 -1
- package/dist/runtime/interpreter.js +2 -0
- package/dist/runtime/interpreter.js.map +1 -1
- package/package.json +2 -2
|
@@ -704,7 +704,7 @@ function addDerivedFormula(state, formula, justification, premises) {
|
|
|
704
704
|
state.known.set(hash, formula);
|
|
705
705
|
return true;
|
|
706
706
|
}
|
|
707
|
-
function tryDerive(goal, theory, premiseNames) {
|
|
707
|
+
function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
708
708
|
const state = {
|
|
709
709
|
known: new Map(),
|
|
710
710
|
steps: [],
|
|
@@ -781,9 +781,10 @@ function tryDerive(goal, theory, premiseNames) {
|
|
|
781
781
|
]) || changed;
|
|
782
782
|
}
|
|
783
783
|
// Conjunction Introduction: de A y B, derivar A & B
|
|
784
|
+
// Only produce conjunctions that are relevant to the goal to avoid O(n²) explosion
|
|
784
785
|
if (f1 !== f2) {
|
|
785
786
|
const conj = { kind: 'and', args: [f1, f2] };
|
|
786
|
-
if (formulasEqual(conj, goal)) {
|
|
787
|
+
if (formulasEqual(conj, goal) || isRelevantToGoal(conj, goal)) {
|
|
787
788
|
changed =
|
|
788
789
|
addDerivedFormula(state, conj, 'Introduccion de conjuncion', [
|
|
789
790
|
findStep(state.steps, f1),
|
|
@@ -909,6 +910,33 @@ function tryDerive(goal, theory, premiseNames) {
|
|
|
909
910
|
}
|
|
910
911
|
}
|
|
911
912
|
}
|
|
913
|
+
// Dilema Constructivo (implicaciones separadas): P->Q, R->S, P|R ⊢ Q|S
|
|
914
|
+
// No requiere que las implicaciones estén en conjunción
|
|
915
|
+
if (f1.kind === 'implies' &&
|
|
916
|
+
f1.args?.[0] &&
|
|
917
|
+
f1.args?.[1] &&
|
|
918
|
+
f2.kind === 'implies' &&
|
|
919
|
+
f2.args?.[0] &&
|
|
920
|
+
f2.args?.[1] &&
|
|
921
|
+
!formulasEqual(f1, f2)) {
|
|
922
|
+
// Search for a disjunction P|R in known formulas
|
|
923
|
+
const p = f1.args[0];
|
|
924
|
+
const q = f1.args[1];
|
|
925
|
+
const r = f2.args[0];
|
|
926
|
+
const s = f2.args[1];
|
|
927
|
+
const disjHash = formulaHash({ kind: 'or', args: [p, r] });
|
|
928
|
+
const disjHashRev = formulaHash({ kind: 'or', args: [r, p] });
|
|
929
|
+
if (state.known.has(disjHash) || state.known.has(disjHashRev)) {
|
|
930
|
+
const qs = { kind: 'or', args: [q, s] };
|
|
931
|
+
const disjFormula = state.known.get(disjHash) || state.known.get(disjHashRev);
|
|
932
|
+
changed =
|
|
933
|
+
addDerivedFormula(state, qs, 'Dilema Constructivo', [
|
|
934
|
+
findStep(state.steps, f1),
|
|
935
|
+
findStep(state.steps, f2),
|
|
936
|
+
findStep(state.steps, disjFormula),
|
|
937
|
+
]) || changed;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
912
940
|
// Resolución: P|Q, !P|R derivar Q|R
|
|
913
941
|
if (f1.kind === 'or' &&
|
|
914
942
|
f1.args?.[0] &&
|
|
@@ -947,7 +975,8 @@ function tryDerive(goal, theory, premiseNames) {
|
|
|
947
975
|
]) || changed;
|
|
948
976
|
}
|
|
949
977
|
}
|
|
950
|
-
// Disjunction Introduction: de A, derivar A | B
|
|
978
|
+
// Disjunction Introduction: de A, derivar A | B
|
|
979
|
+
// Relaxed: also allow intermediate disjunctions that are relevant to goal
|
|
951
980
|
if (goal.kind === 'or' && goal.args?.[0] && goal.args?.[1]) {
|
|
952
981
|
if (formulasEqual(f1, goal.args[0]) || formulasEqual(f1, goal.args[1])) {
|
|
953
982
|
changed =
|
|
@@ -956,6 +985,23 @@ function tryDerive(goal, theory, premiseNames) {
|
|
|
956
985
|
]) || changed;
|
|
957
986
|
}
|
|
958
987
|
}
|
|
988
|
+
// Also check if f1 can form a disjunction relevant to some intermediate goal
|
|
989
|
+
if (goal.kind !== 'or') {
|
|
990
|
+
// If the goal is e.g. (A|B) -> C, and we have A, generate A|B as intermediate
|
|
991
|
+
const checkDisjGoals = (g) => {
|
|
992
|
+
if (g.kind === 'or' && g.args?.[0] && g.args?.[1]) {
|
|
993
|
+
if (formulasEqual(f1, g.args[0]) || formulasEqual(f1, g.args[1])) {
|
|
994
|
+
const disj = { kind: 'or', args: [g.args[0], g.args[1]] };
|
|
995
|
+
changed =
|
|
996
|
+
addDerivedFormula(state, disj, 'Introduccion de disyuncion', [
|
|
997
|
+
findStep(state.steps, f1),
|
|
998
|
+
]) || changed;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
g.args?.forEach(checkDisjGoals);
|
|
1002
|
+
};
|
|
1003
|
+
checkDisjGoals(goal);
|
|
1004
|
+
}
|
|
959
1005
|
// Double Negation Elimination: de !!A, derivar A
|
|
960
1006
|
if (f1.kind === 'not' && f1.args?.[0]?.kind === 'not' && f1.args[0].args?.[0]) {
|
|
961
1007
|
const inner = f1.args[0].args[0];
|
|
@@ -970,13 +1016,14 @@ function tryDerive(goal, theory, premiseNames) {
|
|
|
970
1016
|
findStep(state.steps, f1),
|
|
971
1017
|
]) || changed;
|
|
972
1018
|
}
|
|
973
|
-
//
|
|
1019
|
+
// Weakening (Debilitamiento): si la meta es A -> B y ya conocemos B,
|
|
1020
|
+
// entonces A -> B es válida (B ⊢ A -> B en lógica clásica).
|
|
974
1021
|
if (goal.kind === 'implies' &&
|
|
975
1022
|
goal.args?.[0] &&
|
|
976
1023
|
goal.args?.[1] &&
|
|
977
1024
|
formulasEqual(goal.args[1], f1)) {
|
|
978
1025
|
changed =
|
|
979
|
-
addDerivedFormula(state, goal, '
|
|
1026
|
+
addDerivedFormula(state, goal, 'Debilitamiento (B ⊢ A → B)', [
|
|
980
1027
|
findStep(state.steps, f1),
|
|
981
1028
|
]) || changed;
|
|
982
1029
|
}
|
|
@@ -1081,6 +1128,82 @@ function tryDerive(goal, theory, premiseNames) {
|
|
|
1081
1128
|
changed =
|
|
1082
1129
|
addDerivedFormula(state, dm2, 'De Morgan (OR)', [findStep(state.steps, f1)]) || changed;
|
|
1083
1130
|
}
|
|
1131
|
+
// Distribución 1: P & (Q | R) ⊢ (P & Q) | (P & R)
|
|
1132
|
+
if (f1.kind === 'and' &&
|
|
1133
|
+
f1.args?.[0] &&
|
|
1134
|
+
f1.args?.[1]?.kind === 'or' &&
|
|
1135
|
+
f1.args[1].args?.[0] &&
|
|
1136
|
+
f1.args[1].args?.[1]) {
|
|
1137
|
+
const dist = {
|
|
1138
|
+
kind: 'or',
|
|
1139
|
+
args: [
|
|
1140
|
+
{ kind: 'and', args: [f1.args[0], f1.args[1].args[0]] },
|
|
1141
|
+
{ kind: 'and', args: [f1.args[0], f1.args[1].args[1]] },
|
|
1142
|
+
],
|
|
1143
|
+
};
|
|
1144
|
+
changed =
|
|
1145
|
+
addDerivedFormula(state, dist, 'Distribucion (AND sobre OR)', [
|
|
1146
|
+
findStep(state.steps, f1),
|
|
1147
|
+
]) || changed;
|
|
1148
|
+
}
|
|
1149
|
+
// Distribución 1b: (Q | R) & P ⊢ (Q & P) | (R & P)
|
|
1150
|
+
if (f1.kind === 'and' &&
|
|
1151
|
+
f1.args?.[0]?.kind === 'or' &&
|
|
1152
|
+
f1.args[0].args?.[0] &&
|
|
1153
|
+
f1.args[0].args?.[1] &&
|
|
1154
|
+
f1.args?.[1]) {
|
|
1155
|
+
const dist = {
|
|
1156
|
+
kind: 'or',
|
|
1157
|
+
args: [
|
|
1158
|
+
{ kind: 'and', args: [f1.args[0].args[0], f1.args[1]] },
|
|
1159
|
+
{ kind: 'and', args: [f1.args[0].args[1], f1.args[1]] },
|
|
1160
|
+
],
|
|
1161
|
+
};
|
|
1162
|
+
changed =
|
|
1163
|
+
addDerivedFormula(state, dist, 'Distribucion (AND sobre OR)', [
|
|
1164
|
+
findStep(state.steps, f1),
|
|
1165
|
+
]) || changed;
|
|
1166
|
+
}
|
|
1167
|
+
// Distribución 2: P | (Q & R) ⊢ (P | Q) & (P | R)
|
|
1168
|
+
if (f1.kind === 'or' &&
|
|
1169
|
+
f1.args?.[0] &&
|
|
1170
|
+
f1.args?.[1]?.kind === 'and' &&
|
|
1171
|
+
f1.args[1].args?.[0] &&
|
|
1172
|
+
f1.args[1].args?.[1]) {
|
|
1173
|
+
const dist = {
|
|
1174
|
+
kind: 'and',
|
|
1175
|
+
args: [
|
|
1176
|
+
{ kind: 'or', args: [f1.args[0], f1.args[1].args[0]] },
|
|
1177
|
+
{ kind: 'or', args: [f1.args[0], f1.args[1].args[1]] },
|
|
1178
|
+
],
|
|
1179
|
+
};
|
|
1180
|
+
if (isRelevantToGoal(dist, goal)) {
|
|
1181
|
+
changed =
|
|
1182
|
+
addDerivedFormula(state, dist, 'Distribucion (OR sobre AND)', [
|
|
1183
|
+
findStep(state.steps, f1),
|
|
1184
|
+
]) || changed;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
// Distribución 2b: (Q & R) | P ⊢ (Q | P) & (R | P)
|
|
1188
|
+
if (f1.kind === 'or' &&
|
|
1189
|
+
f1.args?.[0]?.kind === 'and' &&
|
|
1190
|
+
f1.args[0].args?.[0] &&
|
|
1191
|
+
f1.args[0].args?.[1] &&
|
|
1192
|
+
f1.args?.[1]) {
|
|
1193
|
+
const dist = {
|
|
1194
|
+
kind: 'and',
|
|
1195
|
+
args: [
|
|
1196
|
+
{ kind: 'or', args: [f1.args[0].args[0], f1.args[1]] },
|
|
1197
|
+
{ kind: 'or', args: [f1.args[0].args[1], f1.args[1]] },
|
|
1198
|
+
],
|
|
1199
|
+
};
|
|
1200
|
+
if (isRelevantToGoal(dist, goal)) {
|
|
1201
|
+
changed =
|
|
1202
|
+
addDerivedFormula(state, dist, 'Distribucion (OR sobre AND)', [
|
|
1203
|
+
findStep(state.steps, f1),
|
|
1204
|
+
]) || changed;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1084
1207
|
// RAA (Reductio ad Absurdum) #29:
|
|
1085
1208
|
// Si tenemos P→Q y P→¬Q (o ¬Q→P y Q→P), derivar ¬P
|
|
1086
1209
|
if (f1.kind === 'implies' && f1.args?.[0] && f1.args?.[1]) {
|
|
@@ -1135,6 +1258,226 @@ function tryDerive(goal, theory, premiseNames) {
|
|
|
1135
1258
|
derivedFrom: premiseNames,
|
|
1136
1259
|
};
|
|
1137
1260
|
}
|
|
1261
|
+
// --- Sub-derivaciones recursivas (antes del fallback semántico) ---
|
|
1262
|
+
const MAX_SUB_DEPTH = 2;
|
|
1263
|
+
// Prueba Condicional real (→-Introducción / Deduction Theorem):
|
|
1264
|
+
// Para derivar A→B, asumimos A como premisa temporal y derivamos B.
|
|
1265
|
+
if (depth < MAX_SUB_DEPTH &&
|
|
1266
|
+
goal.kind === 'implies' &&
|
|
1267
|
+
goal.args?.[0] &&
|
|
1268
|
+
goal.args?.[1]) {
|
|
1269
|
+
const assumption = goal.args[0];
|
|
1270
|
+
const subGoal = goal.args[1];
|
|
1271
|
+
// Create a temporary theory with the assumption added
|
|
1272
|
+
const tempTheory = {
|
|
1273
|
+
profile: theory.profile,
|
|
1274
|
+
axioms: new Map(theory.axioms),
|
|
1275
|
+
theorems: new Map(theory.theorems),
|
|
1276
|
+
claims: theory.claims,
|
|
1277
|
+
judgments: theory.judgments,
|
|
1278
|
+
};
|
|
1279
|
+
const assumptionName = `__assumption_${depth}_${formulaHash(assumption)}`;
|
|
1280
|
+
tempTheory.axioms.set(assumptionName, assumption);
|
|
1281
|
+
const subPremises = [...premiseNames, assumptionName];
|
|
1282
|
+
const subProof = tryDerive(subGoal, tempTheory, subPremises, depth + 1);
|
|
1283
|
+
if (subProof && subProof.status === 'complete') {
|
|
1284
|
+
// Check the sub-proof doesn't rely solely on semantic fallback
|
|
1285
|
+
const isSyntactic = subProof.steps.every((s) => !s.justification.startsWith('Verificacion semantica'));
|
|
1286
|
+
if (isSyntactic) {
|
|
1287
|
+
// Build the main proof: premises + sub-derivation steps + conditional proof conclusion
|
|
1288
|
+
const mainSteps = [];
|
|
1289
|
+
let stepNum = 0;
|
|
1290
|
+
// Copy premise steps from current state
|
|
1291
|
+
for (const s of state.steps) {
|
|
1292
|
+
if (s.justification.startsWith('Premisa')) {
|
|
1293
|
+
stepNum++;
|
|
1294
|
+
mainSteps.push({ ...s, stepNumber: stepNum, premises: [] });
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
// Add assumption step
|
|
1298
|
+
stepNum++;
|
|
1299
|
+
const assumptionStepNum = stepNum;
|
|
1300
|
+
mainSteps.push({
|
|
1301
|
+
stepNumber: stepNum,
|
|
1302
|
+
formula: assumption,
|
|
1303
|
+
justification: 'Supuesto (para prueba condicional)',
|
|
1304
|
+
premises: [],
|
|
1305
|
+
});
|
|
1306
|
+
// Add sub-derivation steps (renumber, adjusting premise references)
|
|
1307
|
+
const subStepOffset = stepNum;
|
|
1308
|
+
const subStepMap = new Map();
|
|
1309
|
+
for (const s of subProof.steps) {
|
|
1310
|
+
if (s.justification.startsWith('Premisa') && formulasEqual(s.formula, assumption)) {
|
|
1311
|
+
subStepMap.set(s.stepNumber, assumptionStepNum);
|
|
1312
|
+
continue;
|
|
1313
|
+
}
|
|
1314
|
+
if (s.justification.startsWith('Premisa')) {
|
|
1315
|
+
// Find existing premise step in main
|
|
1316
|
+
const existing = mainSteps.find((ms) => ms.justification.startsWith('Premisa') && formulasEqual(ms.formula, s.formula));
|
|
1317
|
+
if (existing) {
|
|
1318
|
+
subStepMap.set(s.stepNumber, existing.stepNumber);
|
|
1319
|
+
continue;
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
stepNum++;
|
|
1323
|
+
subStepMap.set(s.stepNumber, stepNum);
|
|
1324
|
+
mainSteps.push({
|
|
1325
|
+
stepNumber: stepNum,
|
|
1326
|
+
formula: s.formula,
|
|
1327
|
+
justification: s.justification,
|
|
1328
|
+
premises: s.premises.map((p) => subStepMap.get(p) || p),
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1331
|
+
// Add final conditional proof step
|
|
1332
|
+
stepNum++;
|
|
1333
|
+
const subGoalStepNum = subStepMap.get(subProof.steps[subProof.steps.length - 1]?.stepNumber ?? 0) ?? (stepNum - 1);
|
|
1334
|
+
mainSteps.push({
|
|
1335
|
+
stepNumber: stepNum,
|
|
1336
|
+
formula: goal,
|
|
1337
|
+
justification: 'Prueba Condicional (Teorema de Deduccion)',
|
|
1338
|
+
premises: [assumptionStepNum, subGoalStepNum],
|
|
1339
|
+
});
|
|
1340
|
+
return {
|
|
1341
|
+
goal,
|
|
1342
|
+
steps: mainSteps,
|
|
1343
|
+
status: 'complete',
|
|
1344
|
+
derivedFrom: premiseNames,
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
// Prueba por Casos (∨-Eliminación / Disjunction Elimination):
|
|
1350
|
+
// Si tenemos A|B y queremos derivar C, asumimos A→C y B→C por separado.
|
|
1351
|
+
if (depth < MAX_SUB_DEPTH) {
|
|
1352
|
+
const disjunctions = Array.from(state.known.values()).filter((f) => f.kind === 'or' && f.args?.[0] && f.args?.[1]);
|
|
1353
|
+
for (const disj of disjunctions) {
|
|
1354
|
+
const left = disj.args[0];
|
|
1355
|
+
const right = disj.args[1];
|
|
1356
|
+
// Try to derive goal assuming left
|
|
1357
|
+
const tempTheoryL = {
|
|
1358
|
+
profile: theory.profile,
|
|
1359
|
+
axioms: new Map(theory.axioms),
|
|
1360
|
+
theorems: new Map(theory.theorems),
|
|
1361
|
+
claims: theory.claims,
|
|
1362
|
+
judgments: theory.judgments,
|
|
1363
|
+
};
|
|
1364
|
+
const leftName = `__case_left_${depth}_${formulaHash(left)}`;
|
|
1365
|
+
tempTheoryL.axioms.set(leftName, left);
|
|
1366
|
+
const subPremisesL = [...premiseNames, leftName];
|
|
1367
|
+
const subProofL = tryDerive(goal, tempTheoryL, subPremisesL, depth + 1);
|
|
1368
|
+
if (!subProofL || subProofL.status !== 'complete')
|
|
1369
|
+
continue;
|
|
1370
|
+
const isSyntacticL = subProofL.steps.every((s) => !s.justification.startsWith('Verificacion semantica'));
|
|
1371
|
+
if (!isSyntacticL)
|
|
1372
|
+
continue;
|
|
1373
|
+
// Try to derive goal assuming right
|
|
1374
|
+
const tempTheoryR = {
|
|
1375
|
+
profile: theory.profile,
|
|
1376
|
+
axioms: new Map(theory.axioms),
|
|
1377
|
+
theorems: new Map(theory.theorems),
|
|
1378
|
+
claims: theory.claims,
|
|
1379
|
+
judgments: theory.judgments,
|
|
1380
|
+
};
|
|
1381
|
+
const rightName = `__case_right_${depth}_${formulaHash(right)}`;
|
|
1382
|
+
tempTheoryR.axioms.set(rightName, right);
|
|
1383
|
+
const subPremisesR = [...premiseNames, rightName];
|
|
1384
|
+
const subProofR = tryDerive(goal, tempTheoryR, subPremisesR, depth + 1);
|
|
1385
|
+
if (!subProofR || subProofR.status !== 'complete')
|
|
1386
|
+
continue;
|
|
1387
|
+
const isSyntacticR = subProofR.steps.every((s) => !s.justification.startsWith('Verificacion semantica'));
|
|
1388
|
+
if (!isSyntacticR)
|
|
1389
|
+
continue;
|
|
1390
|
+
// Both cases succeed — build proof by cases
|
|
1391
|
+
const mainSteps = [];
|
|
1392
|
+
let stepNum = 0;
|
|
1393
|
+
// Copy premise steps
|
|
1394
|
+
for (const s of state.steps) {
|
|
1395
|
+
if (s.justification.startsWith('Premisa')) {
|
|
1396
|
+
stepNum++;
|
|
1397
|
+
mainSteps.push({ ...s, stepNumber: stepNum, premises: [] });
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
const disjStepNum = mainSteps.find((ms) => formulasEqual(ms.formula, disj))?.stepNumber ?? 0;
|
|
1401
|
+
// Left case sub-derivation
|
|
1402
|
+
stepNum++;
|
|
1403
|
+
const leftAssumptionStep = stepNum;
|
|
1404
|
+
mainSteps.push({
|
|
1405
|
+
stepNumber: stepNum,
|
|
1406
|
+
formula: left,
|
|
1407
|
+
justification: 'Supuesto (caso izquierdo)',
|
|
1408
|
+
premises: [],
|
|
1409
|
+
});
|
|
1410
|
+
const leftStepMap = new Map();
|
|
1411
|
+
for (const s of subProofL.steps) {
|
|
1412
|
+
if (s.justification.startsWith('Premisa') && formulasEqual(s.formula, left)) {
|
|
1413
|
+
leftStepMap.set(s.stepNumber, leftAssumptionStep);
|
|
1414
|
+
continue;
|
|
1415
|
+
}
|
|
1416
|
+
if (s.justification.startsWith('Premisa')) {
|
|
1417
|
+
const existing = mainSteps.find((ms) => ms.justification.startsWith('Premisa') && formulasEqual(ms.formula, s.formula));
|
|
1418
|
+
if (existing) {
|
|
1419
|
+
leftStepMap.set(s.stepNumber, existing.stepNumber);
|
|
1420
|
+
continue;
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
stepNum++;
|
|
1424
|
+
leftStepMap.set(s.stepNumber, stepNum);
|
|
1425
|
+
mainSteps.push({
|
|
1426
|
+
stepNumber: stepNum,
|
|
1427
|
+
formula: s.formula,
|
|
1428
|
+
justification: s.justification,
|
|
1429
|
+
premises: s.premises.map((p) => leftStepMap.get(p) || p),
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
const leftGoalStep = leftStepMap.get(subProofL.steps[subProofL.steps.length - 1]?.stepNumber ?? 0) ?? stepNum;
|
|
1433
|
+
// Right case sub-derivation
|
|
1434
|
+
stepNum++;
|
|
1435
|
+
const rightAssumptionStep = stepNum;
|
|
1436
|
+
mainSteps.push({
|
|
1437
|
+
stepNumber: stepNum,
|
|
1438
|
+
formula: right,
|
|
1439
|
+
justification: 'Supuesto (caso derecho)',
|
|
1440
|
+
premises: [],
|
|
1441
|
+
});
|
|
1442
|
+
const rightStepMap = new Map();
|
|
1443
|
+
for (const s of subProofR.steps) {
|
|
1444
|
+
if (s.justification.startsWith('Premisa') && formulasEqual(s.formula, right)) {
|
|
1445
|
+
rightStepMap.set(s.stepNumber, rightAssumptionStep);
|
|
1446
|
+
continue;
|
|
1447
|
+
}
|
|
1448
|
+
if (s.justification.startsWith('Premisa')) {
|
|
1449
|
+
const existing = mainSteps.find((ms) => ms.justification.startsWith('Premisa') && formulasEqual(ms.formula, s.formula));
|
|
1450
|
+
if (existing) {
|
|
1451
|
+
rightStepMap.set(s.stepNumber, existing.stepNumber);
|
|
1452
|
+
continue;
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
stepNum++;
|
|
1456
|
+
rightStepMap.set(s.stepNumber, stepNum);
|
|
1457
|
+
mainSteps.push({
|
|
1458
|
+
stepNumber: stepNum,
|
|
1459
|
+
formula: s.formula,
|
|
1460
|
+
justification: s.justification,
|
|
1461
|
+
premises: s.premises.map((p) => rightStepMap.get(p) || p),
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
const rightGoalStep = rightStepMap.get(subProofR.steps[subProofR.steps.length - 1]?.stepNumber ?? 0) ?? stepNum;
|
|
1465
|
+
// Final disjunction elimination step
|
|
1466
|
+
stepNum++;
|
|
1467
|
+
mainSteps.push({
|
|
1468
|
+
stepNumber: stepNum,
|
|
1469
|
+
formula: goal,
|
|
1470
|
+
justification: 'Eliminacion de disyuncion (prueba por casos)',
|
|
1471
|
+
premises: [disjStepNum, leftGoalStep, rightGoalStep],
|
|
1472
|
+
});
|
|
1473
|
+
return {
|
|
1474
|
+
goal,
|
|
1475
|
+
steps: mainSteps,
|
|
1476
|
+
status: 'complete',
|
|
1477
|
+
derivedFrom: premiseNames,
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1138
1481
|
// Fallback: verificar semánticamente
|
|
1139
1482
|
const allAxiomFormulas = premiseNames
|
|
1140
1483
|
.map((n) => theory.axioms.get(n) || theory.theorems.get(n))
|
|
@@ -1145,6 +1488,7 @@ function tryDerive(goal, theory, premiseNames) {
|
|
|
1145
1488
|
collectAtoms(f).forEach((a) => atoms.add(a));
|
|
1146
1489
|
collectAtoms(goal).forEach((a) => atoms.add(a));
|
|
1147
1490
|
const atomList = Array.from(atoms).sort();
|
|
1491
|
+
let semanticResult;
|
|
1148
1492
|
// Fast path: bitset semantic check
|
|
1149
1493
|
const allPure = allAxiomFormulas.every(isPurePropositional) && isPurePropositional(goal);
|
|
1150
1494
|
if (allPure && atomList.length <= 26) {
|
|
@@ -1157,19 +1501,10 @@ function tryDerive(goal, theory, premiseNames) {
|
|
|
1157
1501
|
premisesConj = bvAnd(premisesConj, pb);
|
|
1158
1502
|
// Valid if: wherever premises are true, goal is also true
|
|
1159
1503
|
// i.e., premisesConj & ~goalBits === 0
|
|
1160
|
-
|
|
1161
|
-
return {
|
|
1162
|
-
goal,
|
|
1163
|
-
steps: state.steps,
|
|
1164
|
-
status: 'complete',
|
|
1165
|
-
derivedFrom: premiseNames,
|
|
1166
|
-
};
|
|
1167
|
-
}
|
|
1504
|
+
semanticResult = bvIsZero(bvAnd(premisesConj, bvNot(goalBits, allOnes)));
|
|
1168
1505
|
}
|
|
1169
1506
|
else if (allPure && atomList.length > 26) {
|
|
1170
1507
|
// DPLL fallback for >26 atoms
|
|
1171
|
-
// Build: (premise1 & premise2 & ... & premiseN) -> goal
|
|
1172
|
-
// Valid iff NOT satisfiable: (premises & !goal)
|
|
1173
1508
|
let conjunction = allAxiomFormulas[0];
|
|
1174
1509
|
for (let i = 1; i < allAxiomFormulas.length; i++) {
|
|
1175
1510
|
conjunction = { kind: 'and', args: [conjunction, allAxiomFormulas[i]] };
|
|
@@ -1177,34 +1512,47 @@ function tryDerive(goal, theory, premiseNames) {
|
|
|
1177
1512
|
const negGoal = { kind: 'not', args: [goal] };
|
|
1178
1513
|
const check = { kind: 'and', args: [conjunction, negGoal] };
|
|
1179
1514
|
const result = (0, dpll_1.dpll)(check);
|
|
1180
|
-
|
|
1181
|
-
return {
|
|
1182
|
-
goal,
|
|
1183
|
-
steps: state.steps,
|
|
1184
|
-
status: 'complete',
|
|
1185
|
-
derivedFrom: premiseNames,
|
|
1186
|
-
};
|
|
1187
|
-
}
|
|
1515
|
+
semanticResult = !result.satisfiable;
|
|
1188
1516
|
}
|
|
1189
1517
|
else {
|
|
1190
1518
|
// Classic fallback
|
|
1191
1519
|
const valuations = generateValuations(atomList);
|
|
1192
|
-
|
|
1520
|
+
semanticResult = true;
|
|
1193
1521
|
for (const v of valuations) {
|
|
1194
1522
|
const premisesTrue = allAxiomFormulas.every((f) => evaluateClassical(f, v));
|
|
1195
1523
|
if (premisesTrue && !evaluateClassical(goal, v)) {
|
|
1196
|
-
|
|
1524
|
+
semanticResult = false;
|
|
1197
1525
|
break;
|
|
1198
1526
|
}
|
|
1199
1527
|
}
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1528
|
+
}
|
|
1529
|
+
if (semanticResult) {
|
|
1530
|
+
// Generate a synthetic final proof step so the user sees a complete derivation
|
|
1531
|
+
// instead of just "derivado exitosamente" with no proof trace.
|
|
1532
|
+
const goalHash = formulaHash(goal);
|
|
1533
|
+
if (!state.known.has(goalHash)) {
|
|
1534
|
+
const premiseStepNums = premiseNames
|
|
1535
|
+
.map((n) => {
|
|
1536
|
+
const f = theory.axioms.get(n) || theory.theorems.get(n);
|
|
1537
|
+
return f ? findStep(state.steps, f) : 0;
|
|
1538
|
+
})
|
|
1539
|
+
.filter((n) => n > 0);
|
|
1540
|
+
state.stepCount++;
|
|
1541
|
+
state.steps.push({
|
|
1542
|
+
stepNumber: state.stepCount,
|
|
1543
|
+
formula: goal,
|
|
1544
|
+
justification: 'Verificacion semantica (todas las valuaciones satisfacen la consecuencia)',
|
|
1545
|
+
premises: premiseStepNums,
|
|
1546
|
+
});
|
|
1547
|
+
state.known.set(goalHash, goal);
|
|
1207
1548
|
}
|
|
1549
|
+
const relevantSteps = traceBack(state.steps, goal);
|
|
1550
|
+
return {
|
|
1551
|
+
goal,
|
|
1552
|
+
steps: relevantSteps,
|
|
1553
|
+
status: 'complete',
|
|
1554
|
+
derivedFrom: premiseNames,
|
|
1555
|
+
};
|
|
1208
1556
|
}
|
|
1209
1557
|
}
|
|
1210
1558
|
return null;
|