@stevenvo780/st-lang 3.1.3 → 3.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/dist/profiles/classical/cdcl.js +1 -1
- package/dist/profiles/classical/cdcl.js.map +1 -1
- package/dist/profiles/classical/first-order.d.ts +0 -1
- package/dist/profiles/classical/first-order.d.ts.map +1 -1
- package/dist/profiles/classical/first-order.js +181 -81
- 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 +348 -25
- package/dist/profiles/classical/propositional.js.map +1 -1
- package/dist/runtime/fallacies.js +18 -18
- package/dist/runtime/fallacies.js.map +1 -1
- package/dist/tests/core.test.js +133 -1
- package/dist/tests/core.test.js.map +1 -1
- package/dist/tests/propositional-nd-audit.test.d.ts +2 -0
- package/dist/tests/propositional-nd-audit.test.d.ts.map +1 -0
- package/dist/tests/propositional-nd-audit.test.js +116 -0
- package/dist/tests/propositional-nd-audit.test.js.map +1 -0
- package/dist/types/index.d.ts +16 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -796,8 +796,18 @@ function isRelevantToGoal(f, goal) {
|
|
|
796
796
|
}
|
|
797
797
|
function addDerivedFormula(state, formula, justification, premises, source = 'rule') {
|
|
798
798
|
const hash = formulaHash(formula);
|
|
799
|
-
if (state.known.has(hash))
|
|
799
|
+
if (state.known.has(hash)) {
|
|
800
|
+
const variants = state.alternativeDerivations.get(hash) ?? [];
|
|
801
|
+
const isDuplicate = variants.some((variant) => variant.justification === justification &&
|
|
802
|
+
variant.source === source &&
|
|
803
|
+
variant.premises.length === premises.length &&
|
|
804
|
+
variant.premises.every((premise, index) => premise === premises[index]));
|
|
805
|
+
if (!isDuplicate) {
|
|
806
|
+
variants.push({ justification, premises: [...premises], source });
|
|
807
|
+
state.alternativeDerivations.set(hash, variants);
|
|
808
|
+
}
|
|
800
809
|
return false;
|
|
810
|
+
}
|
|
801
811
|
state.stepCount++;
|
|
802
812
|
state.steps.push({
|
|
803
813
|
stepNumber: state.stepCount,
|
|
@@ -807,6 +817,8 @@ function addDerivedFormula(state, formula, justification, premises, source = 'ru
|
|
|
807
817
|
source,
|
|
808
818
|
});
|
|
809
819
|
state.known.set(hash, formula);
|
|
820
|
+
state.formulas.push(formula);
|
|
821
|
+
state.stepByHash.set(hash, state.stepCount);
|
|
810
822
|
return true;
|
|
811
823
|
}
|
|
812
824
|
function buildPremiseRefs(theory, premiseNames) {
|
|
@@ -815,7 +827,12 @@ function buildPremiseRefs(theory, premiseNames) {
|
|
|
815
827
|
location: (theory.axioms.get(name) || theory.theorems.get(name))?.source,
|
|
816
828
|
}));
|
|
817
829
|
}
|
|
818
|
-
function buildProof(goal, steps, premiseNames, theory, method = 'natural_deduction', subproofs) {
|
|
830
|
+
function buildProof(goal, steps, premiseNames, theory, method = 'natural_deduction', subproofs, metadataExtras = {}) {
|
|
831
|
+
const metadata = {
|
|
832
|
+
createdAt: new Date().toISOString(),
|
|
833
|
+
profile: theory.profile,
|
|
834
|
+
...metadataExtras,
|
|
835
|
+
};
|
|
819
836
|
return {
|
|
820
837
|
goal,
|
|
821
838
|
steps,
|
|
@@ -823,11 +840,56 @@ function buildProof(goal, steps, premiseNames, theory, method = 'natural_deducti
|
|
|
823
840
|
derivedFrom: premiseNames,
|
|
824
841
|
premiseRefs: buildPremiseRefs(theory, premiseNames),
|
|
825
842
|
method,
|
|
826
|
-
subproofs,
|
|
827
|
-
metadata
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
843
|
+
subproofs: subproofs ? [...subproofs] : undefined,
|
|
844
|
+
metadata,
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
function buildDerivationMetadata(state, retainedSteps, semanticFallback = false) {
|
|
848
|
+
const sampledAlternatives = Array.from(state.alternativeDerivations.entries())
|
|
849
|
+
.filter(([, variants]) => variants.length > 0)
|
|
850
|
+
.sort((left, right) => right[1].length - left[1].length)
|
|
851
|
+
.slice(0, 12)
|
|
852
|
+
.map(([hash, variants]) => ({
|
|
853
|
+
formula: hash,
|
|
854
|
+
primaryStep: state.stepByHash.get(hash) ?? 0,
|
|
855
|
+
variants: variants.slice(0, 6).map((variant) => ({
|
|
856
|
+
justification: variant.justification,
|
|
857
|
+
premises: [...variant.premises],
|
|
858
|
+
source: variant.source,
|
|
859
|
+
})),
|
|
860
|
+
}));
|
|
861
|
+
const alternativeDerivationCount = Array.from(state.alternativeDerivations.values()).reduce((count, variants) => count + variants.length, 0);
|
|
862
|
+
return {
|
|
863
|
+
exploredStepCount: state.steps.length,
|
|
864
|
+
retainedStepCount: retainedSteps.length,
|
|
865
|
+
uniqueFormulaCount: state.formulas.length,
|
|
866
|
+
alternativeDerivationCount,
|
|
867
|
+
alternativeDerivationSamples: sampledAlternatives,
|
|
868
|
+
semanticFallback,
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
function buildCompositeDerivationMetadata(state, retainedSteps, subProofs = [], semanticFallback = false) {
|
|
872
|
+
const baseMetadata = buildDerivationMetadata(state, retainedSteps, semanticFallback);
|
|
873
|
+
const baseExploredStepCount = Number(baseMetadata.exploredStepCount ?? 0);
|
|
874
|
+
const baseAlternativeDerivationCount = Number(baseMetadata.alternativeDerivationCount ?? 0);
|
|
875
|
+
const subExploredStepCount = subProofs.reduce((count, subProof) => {
|
|
876
|
+
const subMetadata = subProof.metadata ?? {};
|
|
877
|
+
const explored = Number(subMetadata.exploredStepCount ?? subProof.steps.length);
|
|
878
|
+
return count + explored;
|
|
879
|
+
}, 0);
|
|
880
|
+
const subAlternativeDerivationCount = subProofs.reduce((count, subProof) => {
|
|
881
|
+
const subMetadata = subProof.metadata ?? {};
|
|
882
|
+
const alternatives = Number(subMetadata.alternativeDerivationCount ?? 0);
|
|
883
|
+
return count + alternatives;
|
|
884
|
+
}, 0);
|
|
885
|
+
const exploredStepCount = baseExploredStepCount + subExploredStepCount;
|
|
886
|
+
const alternativeDerivationCount = baseAlternativeDerivationCount + subAlternativeDerivationCount;
|
|
887
|
+
return {
|
|
888
|
+
...baseMetadata,
|
|
889
|
+
exploredStepCount,
|
|
890
|
+
retainedStepCount: retainedSteps.length,
|
|
891
|
+
alternativeDerivationCount,
|
|
892
|
+
alternativeDerivationSamples: [],
|
|
831
893
|
};
|
|
832
894
|
}
|
|
833
895
|
function isNegationOf(a, b) {
|
|
@@ -838,6 +900,116 @@ function isExcludedMiddleFormula(formula) {
|
|
|
838
900
|
return false;
|
|
839
901
|
return (isNegationOf(formula.args[0], formula.args[1]) || isNegationOf(formula.args[1], formula.args[0]));
|
|
840
902
|
}
|
|
903
|
+
function buildSingleAssumptionProof(premiseSteps, assumption, assumptionJustification, subProof, goal, finalJustification) {
|
|
904
|
+
const mainSteps = [];
|
|
905
|
+
let stepNum = 0;
|
|
906
|
+
for (const s of premiseSteps) {
|
|
907
|
+
if (s.source === 'premise') {
|
|
908
|
+
stepNum++;
|
|
909
|
+
mainSteps.push({ ...s, stepNumber: stepNum, premises: [] });
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
stepNum++;
|
|
913
|
+
const assumptionStepNum = stepNum;
|
|
914
|
+
mainSteps.push({
|
|
915
|
+
stepNumber: stepNum,
|
|
916
|
+
formula: assumption,
|
|
917
|
+
justification: assumptionJustification,
|
|
918
|
+
premises: [],
|
|
919
|
+
source: 'assumption',
|
|
920
|
+
});
|
|
921
|
+
const subStepMap = new Map();
|
|
922
|
+
for (const s of subProof.steps) {
|
|
923
|
+
if (s.source === 'premise' && formulasEqual(s.formula, assumption)) {
|
|
924
|
+
subStepMap.set(s.stepNumber, assumptionStepNum);
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
if (s.source === 'premise') {
|
|
928
|
+
const existing = mainSteps.find((ms) => ms.source === 'premise' && formulasEqual(ms.formula, s.formula));
|
|
929
|
+
if (existing) {
|
|
930
|
+
subStepMap.set(s.stepNumber, existing.stepNumber);
|
|
931
|
+
continue;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
stepNum++;
|
|
935
|
+
subStepMap.set(s.stepNumber, stepNum);
|
|
936
|
+
mainSteps.push({
|
|
937
|
+
stepNumber: stepNum,
|
|
938
|
+
formula: s.formula,
|
|
939
|
+
justification: s.justification,
|
|
940
|
+
premises: s.premises.map((p) => subStepMap.get(p) || p),
|
|
941
|
+
source: s.source,
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
stepNum++;
|
|
945
|
+
const subGoalStepNum = subStepMap.get(subProof.steps[subProof.steps.length - 1]?.stepNumber ?? 0) ?? stepNum - 1;
|
|
946
|
+
mainSteps.push({
|
|
947
|
+
stepNumber: stepNum,
|
|
948
|
+
formula: goal,
|
|
949
|
+
justification: finalJustification,
|
|
950
|
+
premises: [assumptionStepNum, subGoalStepNum],
|
|
951
|
+
subproofs: [subProof],
|
|
952
|
+
source: 'rule',
|
|
953
|
+
});
|
|
954
|
+
return mainSteps;
|
|
955
|
+
}
|
|
956
|
+
function buildMergedGoalProof(premiseSteps, subProofs, goal, finalJustification) {
|
|
957
|
+
const mainSteps = [];
|
|
958
|
+
let stepNum = 0;
|
|
959
|
+
const baseStepByHash = new Map();
|
|
960
|
+
for (const s of premiseSteps) {
|
|
961
|
+
if (s.source === 'premise') {
|
|
962
|
+
stepNum++;
|
|
963
|
+
mainSteps.push({ ...s, stepNumber: stepNum, premises: [] });
|
|
964
|
+
baseStepByHash.set(formulaHash(s.formula), stepNum);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
const finalPremises = [];
|
|
968
|
+
for (const subProof of subProofs) {
|
|
969
|
+
const stepMap = new Map();
|
|
970
|
+
for (const s of subProof.steps) {
|
|
971
|
+
const hash = formulaHash(s.formula);
|
|
972
|
+
if (s.source === 'premise' && baseStepByHash.has(hash)) {
|
|
973
|
+
stepMap.set(s.stepNumber, baseStepByHash.get(hash) ?? 0);
|
|
974
|
+
continue;
|
|
975
|
+
}
|
|
976
|
+
if (s.source !== 'assumption' && baseStepByHash.has(hash)) {
|
|
977
|
+
stepMap.set(s.stepNumber, baseStepByHash.get(hash) ?? 0);
|
|
978
|
+
continue;
|
|
979
|
+
}
|
|
980
|
+
stepNum++;
|
|
981
|
+
stepMap.set(s.stepNumber, stepNum);
|
|
982
|
+
mainSteps.push({
|
|
983
|
+
stepNumber: stepNum,
|
|
984
|
+
formula: s.formula,
|
|
985
|
+
justification: s.justification,
|
|
986
|
+
premises: s.premises.map((p) => stepMap.get(p) || p),
|
|
987
|
+
subproofs: s.subproofs ? [...s.subproofs] : undefined,
|
|
988
|
+
source: s.source,
|
|
989
|
+
});
|
|
990
|
+
if (s.source !== 'assumption') {
|
|
991
|
+
baseStepByHash.set(hash, stepNum);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
const mappedFinal = stepMap.get(subProof.steps[subProof.steps.length - 1]?.stepNumber ?? 0);
|
|
995
|
+
if (mappedFinal)
|
|
996
|
+
finalPremises.push(mappedFinal);
|
|
997
|
+
}
|
|
998
|
+
stepNum++;
|
|
999
|
+
mainSteps.push({
|
|
1000
|
+
stepNumber: stepNum,
|
|
1001
|
+
formula: goal,
|
|
1002
|
+
justification: finalJustification,
|
|
1003
|
+
premises: finalPremises,
|
|
1004
|
+
subproofs: subProofs,
|
|
1005
|
+
source: 'rule',
|
|
1006
|
+
});
|
|
1007
|
+
return mainSteps;
|
|
1008
|
+
}
|
|
1009
|
+
function buildKnownDerivationProof(state, formula, premiseNames, theory) {
|
|
1010
|
+
const relevantSteps = traceBack(state.steps, formula);
|
|
1011
|
+
return buildProof(formula, relevantSteps, premiseNames, theory, 'natural_deduction', undefined, buildDerivationMetadata(state, relevantSteps));
|
|
1012
|
+
}
|
|
841
1013
|
function getCommutativeVariant(formula) {
|
|
842
1014
|
if ((formula.kind === 'and' || formula.kind === 'or') && formula.args?.[0] && formula.args?.[1]) {
|
|
843
1015
|
return { kind: formula.kind, args: [formula.args[1], formula.args[0]] };
|
|
@@ -883,8 +1055,11 @@ function getAbsorptionResult(formula) {
|
|
|
883
1055
|
function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
884
1056
|
const state = {
|
|
885
1057
|
known: new Map(),
|
|
1058
|
+
formulas: [],
|
|
886
1059
|
steps: [],
|
|
887
1060
|
stepCount: 0,
|
|
1061
|
+
stepByHash: new Map(),
|
|
1062
|
+
alternativeDerivations: new Map(),
|
|
888
1063
|
};
|
|
889
1064
|
// Cargar premisas
|
|
890
1065
|
for (const name of premiseNames) {
|
|
@@ -917,6 +1092,8 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
917
1092
|
source: 'premise',
|
|
918
1093
|
});
|
|
919
1094
|
state.known.set(formulaHash(f), f);
|
|
1095
|
+
state.formulas.push(f);
|
|
1096
|
+
state.stepByHash.set(formulaHash(f), state.stepCount);
|
|
920
1097
|
}
|
|
921
1098
|
}
|
|
922
1099
|
if (isExcludedMiddleFormula(goal)) {
|
|
@@ -930,7 +1107,7 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
930
1107
|
while (changed && iterations < maxIterations && state.known.size < MAX_KNOWN) {
|
|
931
1108
|
changed = false;
|
|
932
1109
|
iterations++;
|
|
933
|
-
const currentFormulas =
|
|
1110
|
+
const currentFormulas = state.formulas;
|
|
934
1111
|
const prevProcessedIndex = lastProcessedIndex;
|
|
935
1112
|
lastProcessedIndex = currentFormulas.length;
|
|
936
1113
|
for (let i = 0; i < currentFormulas.length; i++) {
|
|
@@ -944,6 +1121,15 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
944
1121
|
const f2 = currentFormulas[j];
|
|
945
1122
|
if (state.known.has(formulaHash(goal)))
|
|
946
1123
|
break;
|
|
1124
|
+
// Contradicción explícita: de A y !A, derivar false (⊥)
|
|
1125
|
+
if ((f1.kind === 'not' && f1.args?.[0] && formulasEqual(f1.args[0], f2)) ||
|
|
1126
|
+
(f2.kind === 'not' && f2.args?.[0] && formulasEqual(f2.args[0], f1))) {
|
|
1127
|
+
changed =
|
|
1128
|
+
addDerivedFormula(state, { kind: 'false' }, 'Contradiccion', [
|
|
1129
|
+
findStep(state.steps, f1),
|
|
1130
|
+
findStep(state.steps, f2),
|
|
1131
|
+
]) || changed;
|
|
1132
|
+
}
|
|
947
1133
|
// Modus Ponens: de A y (A -> B), derivar B
|
|
948
1134
|
if (f2.kind === 'implies' &&
|
|
949
1135
|
f2.args?.[0] &&
|
|
@@ -978,6 +1164,19 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
978
1164
|
findStep(state.steps, f2),
|
|
979
1165
|
]) || changed;
|
|
980
1166
|
}
|
|
1167
|
+
// Modus Tollens con consecuente negado: de B y (A -> !B), derivar !A
|
|
1168
|
+
if (f2.kind === 'implies' &&
|
|
1169
|
+
f2.args?.[0] &&
|
|
1170
|
+
f2.args?.[1]?.kind === 'not' &&
|
|
1171
|
+
f2.args[1].args?.[0] &&
|
|
1172
|
+
formulasEqual(f1, f2.args[1].args[0])) {
|
|
1173
|
+
const conclusion = { kind: 'not', args: [f2.args[0]] };
|
|
1174
|
+
changed =
|
|
1175
|
+
addDerivedFormula(state, conclusion, 'Modus Tollens', [
|
|
1176
|
+
findStep(state.steps, f1),
|
|
1177
|
+
findStep(state.steps, f2),
|
|
1178
|
+
]) || changed;
|
|
1179
|
+
}
|
|
981
1180
|
// Conjunction Introduction: de A y B, derivar A & B
|
|
982
1181
|
// Only produce conjunctions that are relevant to the goal to avoid O(n²) explosion
|
|
983
1182
|
if (f1 !== f2) {
|
|
@@ -1166,6 +1365,11 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
1166
1365
|
]) || changed;
|
|
1167
1366
|
}
|
|
1168
1367
|
}
|
|
1368
|
+
// Eliminación de contradicción: de false (⊥), derivar cualquier meta
|
|
1369
|
+
if (f1.kind === 'false' && !formulasEqual(f1, goal)) {
|
|
1370
|
+
changed =
|
|
1371
|
+
addDerivedFormula(state, goal, 'Explosion', [findStep(state.steps, f1)]) || changed;
|
|
1372
|
+
}
|
|
1169
1373
|
// Conjunction Elimination: de A & B, derivar A y B
|
|
1170
1374
|
if (f1.kind === 'and' && f1.args) {
|
|
1171
1375
|
for (const sub of f1.args) {
|
|
@@ -1506,10 +1710,10 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
1506
1710
|
if (state.known.has(formulaHash(goal))) {
|
|
1507
1711
|
// Filtrar solo pasos relevantes para la derivación
|
|
1508
1712
|
const relevantSteps = traceBack(state.steps, goal);
|
|
1509
|
-
return buildProof(goal, relevantSteps, premiseNames, theory);
|
|
1713
|
+
return buildProof(goal, relevantSteps, premiseNames, theory, 'natural_deduction', undefined, buildDerivationMetadata(state, relevantSteps));
|
|
1510
1714
|
}
|
|
1511
1715
|
// --- Sub-derivaciones recursivas (antes del fallback semántico) ---
|
|
1512
|
-
const MAX_SUB_DEPTH =
|
|
1716
|
+
const MAX_SUB_DEPTH = 3;
|
|
1513
1717
|
// Prueba Condicional real (→-Introducción / Deduction Theorem):
|
|
1514
1718
|
// Para derivar A→B, asumimos A como premisa temporal y derivamos B.
|
|
1515
1719
|
if (depth < MAX_SUB_DEPTH && goal.kind === 'implies' && goal.args?.[0] && goal.args?.[1]) {
|
|
@@ -1587,14 +1791,14 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
1587
1791
|
subproofs: [subProof],
|
|
1588
1792
|
source: 'rule',
|
|
1589
1793
|
});
|
|
1590
|
-
return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [subProof]);
|
|
1794
|
+
return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [subProof], buildCompositeDerivationMetadata(state, mainSteps, [subProof]));
|
|
1591
1795
|
}
|
|
1592
1796
|
}
|
|
1593
1797
|
}
|
|
1594
1798
|
// Prueba por Casos (∨-Eliminación / Disjunction Elimination):
|
|
1595
1799
|
// Si tenemos A|B y queremos derivar C, asumimos A→C y B→C por separado.
|
|
1596
1800
|
if (depth < MAX_SUB_DEPTH) {
|
|
1597
|
-
const disjunctions =
|
|
1801
|
+
const disjunctions = state.formulas.filter((f) => f.kind === 'or' && f.args?.[0] && f.args?.[1]);
|
|
1598
1802
|
for (const disj of disjunctions) {
|
|
1599
1803
|
const left = disj.args?.[0];
|
|
1600
1804
|
const right = disj.args?.[1];
|
|
@@ -1723,10 +1927,113 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
1723
1927
|
subproofs: [subProofL, subProofR],
|
|
1724
1928
|
source: 'rule',
|
|
1725
1929
|
});
|
|
1726
|
-
return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1930
|
+
return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [subProofL, subProofR], buildCompositeDerivationMetadata(state, mainSteps, [subProofL, subProofR]));
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
// Backchaining dirigido por meta: si tenemos A → objetivo,
|
|
1934
|
+
// intentamos derivar A para cerrar con Modus Ponens sin esperar a que aparezca espontáneamente.
|
|
1935
|
+
if (depth < MAX_SUB_DEPTH) {
|
|
1936
|
+
const candidateImplications = state.formulas.filter((formula) => formula.kind === 'implies' &&
|
|
1937
|
+
!!formula.args?.[0] &&
|
|
1938
|
+
!!formula.args?.[1] &&
|
|
1939
|
+
formulasEqual(formula.args[1], goal));
|
|
1940
|
+
for (const implication of candidateImplications) {
|
|
1941
|
+
const antecedent = implication.args?.[0];
|
|
1942
|
+
if (!antecedent || formulasEqual(antecedent, goal))
|
|
1943
|
+
continue;
|
|
1944
|
+
const antecedentProof = tryDerive(antecedent, theory, premiseNames, depth + 1);
|
|
1945
|
+
if (!antecedentProof || antecedentProof.status !== 'complete')
|
|
1946
|
+
continue;
|
|
1947
|
+
const antecedentIsSyntactic = antecedentProof.steps.every((step) => step.source !== 'semantic');
|
|
1948
|
+
if (!antecedentIsSyntactic)
|
|
1949
|
+
continue;
|
|
1950
|
+
const implicationProof = buildKnownDerivationProof(state, implication, premiseNames, theory);
|
|
1951
|
+
const mainSteps = buildMergedGoalProof(state.steps, [implicationProof, antecedentProof], goal, 'Modus Ponens');
|
|
1952
|
+
return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [implicationProof, antecedentProof], buildCompositeDerivationMetadata(state, mainSteps, [implicationProof, antecedentProof]));
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
// Meta conjuntiva (∧-Introducción dirigida por meta): derivar ambos componentes por separado.
|
|
1956
|
+
if (depth < MAX_SUB_DEPTH && goal.kind === 'and' && goal.args?.[0] && goal.args?.[1]) {
|
|
1957
|
+
const leftGoal = goal.args[0];
|
|
1958
|
+
const rightGoal = goal.args[1];
|
|
1959
|
+
const leftProof = tryDerive(leftGoal, theory, premiseNames, depth + 1);
|
|
1960
|
+
const rightProof = tryDerive(rightGoal, theory, premiseNames, depth + 1);
|
|
1961
|
+
if (leftProof &&
|
|
1962
|
+
rightProof &&
|
|
1963
|
+
leftProof.status === 'complete' &&
|
|
1964
|
+
rightProof.status === 'complete') {
|
|
1965
|
+
const leftSyntactic = leftProof.steps.every((s) => s.source !== 'semantic');
|
|
1966
|
+
const rightSyntactic = rightProof.steps.every((s) => s.source !== 'semantic');
|
|
1967
|
+
if (leftSyntactic && rightSyntactic) {
|
|
1968
|
+
const mainSteps = buildMergedGoalProof(state.steps, [leftProof, rightProof], goal, 'Introduccion de conjuncion');
|
|
1969
|
+
return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [leftProof, rightProof], buildCompositeDerivationMetadata(state, mainSteps, [leftProof, rightProof]));
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
// Meta bicondicional (↔-Introducción dirigida por meta): demostrar ambos sentidos.
|
|
1974
|
+
if (depth < MAX_SUB_DEPTH && goal.kind === 'biconditional' && goal.args?.[0] && goal.args?.[1]) {
|
|
1975
|
+
const leftToRight = { kind: 'implies', args: [goal.args[0], goal.args[1]] };
|
|
1976
|
+
const rightToLeft = { kind: 'implies', args: [goal.args[1], goal.args[0]] };
|
|
1977
|
+
const leftProof = tryDerive(leftToRight, theory, premiseNames, depth + 1);
|
|
1978
|
+
const rightProof = tryDerive(rightToLeft, theory, premiseNames, depth + 1);
|
|
1979
|
+
if (leftProof &&
|
|
1980
|
+
rightProof &&
|
|
1981
|
+
leftProof.status === 'complete' &&
|
|
1982
|
+
rightProof.status === 'complete') {
|
|
1983
|
+
const leftSyntactic = leftProof.steps.every((s) => s.source !== 'semantic');
|
|
1984
|
+
const rightSyntactic = rightProof.steps.every((s) => s.source !== 'semantic');
|
|
1985
|
+
if (leftSyntactic && rightSyntactic) {
|
|
1986
|
+
const mainSteps = buildMergedGoalProof(state.steps, [leftProof, rightProof], goal, 'Introduccion de bicondicional');
|
|
1987
|
+
return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [leftProof, rightProof], buildCompositeDerivationMetadata(state, mainSteps, [leftProof, rightProof]));
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
// Introducción de negación (¬-Introducción): para derivar ¬A,
|
|
1992
|
+
// asumimos A y derivamos contradicción explícita (false / ⊥).
|
|
1993
|
+
if (depth < MAX_SUB_DEPTH && goal.kind === 'not' && goal.args?.[0]) {
|
|
1994
|
+
const assumption = goal.args[0];
|
|
1995
|
+
const contradiction = { kind: 'false' };
|
|
1996
|
+
const tempTheory = {
|
|
1997
|
+
profile: theory.profile,
|
|
1998
|
+
axioms: new Map(theory.axioms),
|
|
1999
|
+
theorems: new Map(theory.theorems),
|
|
2000
|
+
claims: theory.claims,
|
|
2001
|
+
judgments: theory.judgments,
|
|
2002
|
+
};
|
|
2003
|
+
const assumptionName = `__neg_assumption_${depth}_${formulaHash(assumption)}`;
|
|
2004
|
+
tempTheory.axioms.set(assumptionName, assumption);
|
|
2005
|
+
const subPremises = [...premiseNames, assumptionName];
|
|
2006
|
+
const subProof = tryDerive(contradiction, tempTheory, subPremises, depth + 1);
|
|
2007
|
+
if (subProof && subProof.status === 'complete') {
|
|
2008
|
+
const isSyntactic = subProof.steps.every((s) => s.source !== 'semantic');
|
|
2009
|
+
if (isSyntactic) {
|
|
2010
|
+
const mainSteps = buildSingleAssumptionProof(state.steps, assumption, 'Supuesto (para negacion)', subProof, goal, 'Introduccion de negacion');
|
|
2011
|
+
return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [subProof], buildCompositeDerivationMetadata(state, mainSteps, [subProof]));
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
// RAA genérica: para derivar A en lógica clásica,
|
|
2016
|
+
// asumimos ¬A y buscamos contradicción explícita.
|
|
2017
|
+
if (depth < MAX_SUB_DEPTH && goal.kind !== 'not' && goal.kind !== 'false') {
|
|
2018
|
+
const assumption = { kind: 'not', args: [goal] };
|
|
2019
|
+
const contradiction = { kind: 'false' };
|
|
2020
|
+
const tempTheory = {
|
|
2021
|
+
profile: theory.profile,
|
|
2022
|
+
axioms: new Map(theory.axioms),
|
|
2023
|
+
theorems: new Map(theory.theorems),
|
|
2024
|
+
claims: theory.claims,
|
|
2025
|
+
judgments: theory.judgments,
|
|
2026
|
+
};
|
|
2027
|
+
const assumptionName = `__raa_assumption_${depth}_${formulaHash(assumption)}`;
|
|
2028
|
+
tempTheory.axioms.set(assumptionName, assumption);
|
|
2029
|
+
const subPremises = [...premiseNames, assumptionName];
|
|
2030
|
+
const subProof = tryDerive(contradiction, tempTheory, subPremises, depth + 1);
|
|
2031
|
+
if (subProof && subProof.status === 'complete') {
|
|
2032
|
+
const isSyntactic = subProof.steps.every((s) => s.source !== 'semantic');
|
|
2033
|
+
if (isSyntactic) {
|
|
2034
|
+
const mainSteps = buildSingleAssumptionProof(state.steps, assumption, 'Supuesto (para RAA)', subProof, goal, 'RAA (Reduccion al Absurdo)');
|
|
2035
|
+
return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [subProof], buildCompositeDerivationMetadata(state, mainSteps, [subProof]));
|
|
2036
|
+
}
|
|
1730
2037
|
}
|
|
1731
2038
|
}
|
|
1732
2039
|
// Fallback: verificar semánticamente
|
|
@@ -1799,13 +2106,19 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
1799
2106
|
state.known.set(goalHash, goal);
|
|
1800
2107
|
}
|
|
1801
2108
|
const relevantSteps = traceBack(state.steps, goal);
|
|
1802
|
-
return buildProof(goal, relevantSteps, premiseNames, theory, 'semantic');
|
|
2109
|
+
return buildProof(goal, relevantSteps, premiseNames, theory, 'semantic', undefined, buildDerivationMetadata(state, relevantSteps, true));
|
|
1803
2110
|
}
|
|
1804
2111
|
}
|
|
1805
2112
|
return null;
|
|
1806
2113
|
}
|
|
1807
|
-
function findStep(
|
|
2114
|
+
function findStep(stateOrSteps, formula) {
|
|
1808
2115
|
const hash = formulaHash(formula);
|
|
2116
|
+
if (!Array.isArray(stateOrSteps)) {
|
|
2117
|
+
const cached = stateOrSteps.stepByHash.get(hash);
|
|
2118
|
+
if (cached !== undefined)
|
|
2119
|
+
return cached;
|
|
2120
|
+
}
|
|
2121
|
+
const steps = Array.isArray(stateOrSteps) ? stateOrSteps : stateOrSteps.steps;
|
|
1809
2122
|
for (const s of steps) {
|
|
1810
2123
|
if (formulaHash(s.formula) === hash)
|
|
1811
2124
|
return s.stepNumber;
|
|
@@ -2191,13 +2504,23 @@ class ClassicalPropositional {
|
|
|
2191
2504
|
: `${formulaToString(goal)} derivado exitosamente`,
|
|
2192
2505
|
proof,
|
|
2193
2506
|
reasoningType,
|
|
2194
|
-
reasoningSchema: rulesUsed.has('
|
|
2195
|
-
? 'φ
|
|
2196
|
-
: rulesUsed.has('
|
|
2197
|
-
? '
|
|
2198
|
-
: rulesUsed.has('
|
|
2199
|
-
? '
|
|
2200
|
-
:
|
|
2507
|
+
reasoningSchema: rulesUsed.has('Introduccion de negacion')
|
|
2508
|
+
? '[φ] ⊢ ⊥, por lo tanto ¬φ'
|
|
2509
|
+
: rulesUsed.has('RAA (Reduccion al Absurdo)')
|
|
2510
|
+
? '[¬φ] ⊢ ⊥, por lo tanto φ'
|
|
2511
|
+
: rulesUsed.has('Contradiccion')
|
|
2512
|
+
? 'φ, ¬φ ⊢ ⊥'
|
|
2513
|
+
: rulesUsed.has('Explosion')
|
|
2514
|
+
? '⊥ ⊢ ψ'
|
|
2515
|
+
: rulesUsed.has('Prueba Condicional (Teorema de Deduccion)')
|
|
2516
|
+
? '[φ] ⊢ ψ, por lo tanto φ → ψ'
|
|
2517
|
+
: rulesUsed.has('Modus Ponens')
|
|
2518
|
+
? 'φ → ψ, φ ⊢ ψ'
|
|
2519
|
+
: rulesUsed.has('Modus Tollens')
|
|
2520
|
+
? 'φ → ψ, ¬ψ ⊢ ¬φ'
|
|
2521
|
+
: rulesUsed.has('Silogismo Hipotetico')
|
|
2522
|
+
? 'φ → ψ, ψ → χ ⊢ φ → χ'
|
|
2523
|
+
: undefined,
|
|
2201
2524
|
educationalNote: (0, educational_notes_1.pickEducationalNote)({
|
|
2202
2525
|
op: 'derive',
|
|
2203
2526
|
ok: true,
|