@stevenvo780/st-lang 3.1.2 → 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/cli/index.js +6 -11
- package/dist/cli/index.js.map +1 -1
- package/dist/parser/parser.d.ts.map +1 -1
- package/dist/parser/parser.js +29 -6
- package/dist/parser/parser.js.map +1 -1
- 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 +182 -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 +353 -27
- package/dist/profiles/classical/propositional.js.map +1 -1
- package/dist/profiles/intuitionistic/propositional.d.ts.map +1 -1
- package/dist/profiles/intuitionistic/propositional.js +21 -2
- package/dist/profiles/intuitionistic/propositional.js.map +1 -1
- package/dist/profiles/paraconsistent/belnap.d.ts.map +1 -1
- package/dist/profiles/paraconsistent/belnap.js +1 -0
- 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 +1 -0
- package/dist/profiles/probabilistic/basic.js.map +1 -1
- package/dist/profiles/shared/base-profile.d.ts.map +1 -1
- package/dist/profiles/shared/base-profile.js +1 -0
- package/dist/profiles/shared/base-profile.js.map +1 -1
- package/dist/profiles/shared/tableau-engine.d.ts +6 -0
- package/dist/profiles/shared/tableau-engine.d.ts.map +1 -1
- package/dist/profiles/shared/tableau-engine.js +33 -6
- package/dist/profiles/shared/tableau-engine.js.map +1 -1
- package/dist/profiles/temporal/ltl.d.ts +2 -1
- package/dist/profiles/temporal/ltl.d.ts.map +1 -1
- package/dist/profiles/temporal/ltl.js +5 -1
- package/dist/profiles/temporal/ltl.js.map +1 -1
- package/dist/protocol/handler.d.ts +0 -2
- package/dist/protocol/handler.d.ts.map +1 -1
- package/dist/protocol/handler.js +2 -6
- package/dist/protocol/handler.js.map +1 -1
- package/dist/runtime/fallacies.js +18 -18
- package/dist/runtime/fallacies.js.map +1 -1
- package/dist/runtime/interpreter.d.ts +8 -0
- package/dist/runtime/interpreter.d.ts.map +1 -1
- package/dist/runtime/interpreter.js +188 -49
- package/dist/runtime/interpreter.js.map +1 -1
- package/dist/runtime/known-theorems.d.ts.map +1 -1
- package/dist/runtime/known-theorems.js +17 -5
- package/dist/runtime/known-theorems.js.map +1 -1
- package/dist/tests/core.test.js +133 -1
- package/dist/tests/core.test.js.map +1 -1
- package/dist/tests/parser.test.js +10 -0
- package/dist/tests/parser.test.js.map +1 -1
- package/dist/tests/profiles.test.js +16 -0
- package/dist/tests/profiles.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/tests/protocol-text-layer.test.js +18 -0
- package/dist/tests/protocol-text-layer.test.js.map +1 -1
- package/dist/tests/regressions.test.d.ts +2 -0
- package/dist/tests/regressions.test.d.ts.map +1 -0
- package/dist/tests/regressions.test.js +167 -0
- package/dist/tests/regressions.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
|
@@ -110,11 +110,14 @@ function* generateValuationsLazy(atoms) {
|
|
|
110
110
|
yield {};
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
|
-
|
|
113
|
+
if (n > 23)
|
|
114
|
+
throw new Error('Demasiadas variables para tabla de verdad (>23)');
|
|
115
|
+
const total = 2 ** n;
|
|
114
116
|
for (let i = 0; i < total; i++) {
|
|
115
117
|
const v = {};
|
|
116
118
|
for (let j = 0; j < n; j++) {
|
|
117
|
-
|
|
119
|
+
const divisor = 2 ** (n - 1 - j);
|
|
120
|
+
v[atoms[j]] = Math.floor(i / divisor) % 2 === 1;
|
|
118
121
|
}
|
|
119
122
|
yield v;
|
|
120
123
|
}
|
|
@@ -793,8 +796,18 @@ function isRelevantToGoal(f, goal) {
|
|
|
793
796
|
}
|
|
794
797
|
function addDerivedFormula(state, formula, justification, premises, source = 'rule') {
|
|
795
798
|
const hash = formulaHash(formula);
|
|
796
|
-
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
|
+
}
|
|
797
809
|
return false;
|
|
810
|
+
}
|
|
798
811
|
state.stepCount++;
|
|
799
812
|
state.steps.push({
|
|
800
813
|
stepNumber: state.stepCount,
|
|
@@ -804,6 +817,8 @@ function addDerivedFormula(state, formula, justification, premises, source = 'ru
|
|
|
804
817
|
source,
|
|
805
818
|
});
|
|
806
819
|
state.known.set(hash, formula);
|
|
820
|
+
state.formulas.push(formula);
|
|
821
|
+
state.stepByHash.set(hash, state.stepCount);
|
|
807
822
|
return true;
|
|
808
823
|
}
|
|
809
824
|
function buildPremiseRefs(theory, premiseNames) {
|
|
@@ -812,7 +827,12 @@ function buildPremiseRefs(theory, premiseNames) {
|
|
|
812
827
|
location: (theory.axioms.get(name) || theory.theorems.get(name))?.source,
|
|
813
828
|
}));
|
|
814
829
|
}
|
|
815
|
-
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
|
+
};
|
|
816
836
|
return {
|
|
817
837
|
goal,
|
|
818
838
|
steps,
|
|
@@ -820,11 +840,56 @@ function buildProof(goal, steps, premiseNames, theory, method = 'natural_deducti
|
|
|
820
840
|
derivedFrom: premiseNames,
|
|
821
841
|
premiseRefs: buildPremiseRefs(theory, premiseNames),
|
|
822
842
|
method,
|
|
823
|
-
subproofs,
|
|
824
|
-
metadata
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
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: [],
|
|
828
893
|
};
|
|
829
894
|
}
|
|
830
895
|
function isNegationOf(a, b) {
|
|
@@ -835,6 +900,116 @@ function isExcludedMiddleFormula(formula) {
|
|
|
835
900
|
return false;
|
|
836
901
|
return (isNegationOf(formula.args[0], formula.args[1]) || isNegationOf(formula.args[1], formula.args[0]));
|
|
837
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
|
+
}
|
|
838
1013
|
function getCommutativeVariant(formula) {
|
|
839
1014
|
if ((formula.kind === 'and' || formula.kind === 'or') && formula.args?.[0] && formula.args?.[1]) {
|
|
840
1015
|
return { kind: formula.kind, args: [formula.args[1], formula.args[0]] };
|
|
@@ -880,8 +1055,11 @@ function getAbsorptionResult(formula) {
|
|
|
880
1055
|
function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
881
1056
|
const state = {
|
|
882
1057
|
known: new Map(),
|
|
1058
|
+
formulas: [],
|
|
883
1059
|
steps: [],
|
|
884
1060
|
stepCount: 0,
|
|
1061
|
+
stepByHash: new Map(),
|
|
1062
|
+
alternativeDerivations: new Map(),
|
|
885
1063
|
};
|
|
886
1064
|
// Cargar premisas
|
|
887
1065
|
for (const name of premiseNames) {
|
|
@@ -914,6 +1092,8 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
914
1092
|
source: 'premise',
|
|
915
1093
|
});
|
|
916
1094
|
state.known.set(formulaHash(f), f);
|
|
1095
|
+
state.formulas.push(f);
|
|
1096
|
+
state.stepByHash.set(formulaHash(f), state.stepCount);
|
|
917
1097
|
}
|
|
918
1098
|
}
|
|
919
1099
|
if (isExcludedMiddleFormula(goal)) {
|
|
@@ -927,7 +1107,7 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
927
1107
|
while (changed && iterations < maxIterations && state.known.size < MAX_KNOWN) {
|
|
928
1108
|
changed = false;
|
|
929
1109
|
iterations++;
|
|
930
|
-
const currentFormulas =
|
|
1110
|
+
const currentFormulas = state.formulas;
|
|
931
1111
|
const prevProcessedIndex = lastProcessedIndex;
|
|
932
1112
|
lastProcessedIndex = currentFormulas.length;
|
|
933
1113
|
for (let i = 0; i < currentFormulas.length; i++) {
|
|
@@ -941,6 +1121,15 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
941
1121
|
const f2 = currentFormulas[j];
|
|
942
1122
|
if (state.known.has(formulaHash(goal)))
|
|
943
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
|
+
}
|
|
944
1133
|
// Modus Ponens: de A y (A -> B), derivar B
|
|
945
1134
|
if (f2.kind === 'implies' &&
|
|
946
1135
|
f2.args?.[0] &&
|
|
@@ -975,6 +1164,19 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
975
1164
|
findStep(state.steps, f2),
|
|
976
1165
|
]) || changed;
|
|
977
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
|
+
}
|
|
978
1180
|
// Conjunction Introduction: de A y B, derivar A & B
|
|
979
1181
|
// Only produce conjunctions that are relevant to the goal to avoid O(n²) explosion
|
|
980
1182
|
if (f1 !== f2) {
|
|
@@ -1163,6 +1365,11 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
1163
1365
|
]) || changed;
|
|
1164
1366
|
}
|
|
1165
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
|
+
}
|
|
1166
1373
|
// Conjunction Elimination: de A & B, derivar A y B
|
|
1167
1374
|
if (f1.kind === 'and' && f1.args) {
|
|
1168
1375
|
for (const sub of f1.args) {
|
|
@@ -1503,10 +1710,10 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
1503
1710
|
if (state.known.has(formulaHash(goal))) {
|
|
1504
1711
|
// Filtrar solo pasos relevantes para la derivación
|
|
1505
1712
|
const relevantSteps = traceBack(state.steps, goal);
|
|
1506
|
-
return buildProof(goal, relevantSteps, premiseNames, theory);
|
|
1713
|
+
return buildProof(goal, relevantSteps, premiseNames, theory, 'natural_deduction', undefined, buildDerivationMetadata(state, relevantSteps));
|
|
1507
1714
|
}
|
|
1508
1715
|
// --- Sub-derivaciones recursivas (antes del fallback semántico) ---
|
|
1509
|
-
const MAX_SUB_DEPTH =
|
|
1716
|
+
const MAX_SUB_DEPTH = 3;
|
|
1510
1717
|
// Prueba Condicional real (→-Introducción / Deduction Theorem):
|
|
1511
1718
|
// Para derivar A→B, asumimos A como premisa temporal y derivamos B.
|
|
1512
1719
|
if (depth < MAX_SUB_DEPTH && goal.kind === 'implies' && goal.args?.[0] && goal.args?.[1]) {
|
|
@@ -1584,14 +1791,14 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
1584
1791
|
subproofs: [subProof],
|
|
1585
1792
|
source: 'rule',
|
|
1586
1793
|
});
|
|
1587
|
-
return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [subProof]);
|
|
1794
|
+
return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [subProof], buildCompositeDerivationMetadata(state, mainSteps, [subProof]));
|
|
1588
1795
|
}
|
|
1589
1796
|
}
|
|
1590
1797
|
}
|
|
1591
1798
|
// Prueba por Casos (∨-Eliminación / Disjunction Elimination):
|
|
1592
1799
|
// Si tenemos A|B y queremos derivar C, asumimos A→C y B→C por separado.
|
|
1593
1800
|
if (depth < MAX_SUB_DEPTH) {
|
|
1594
|
-
const disjunctions =
|
|
1801
|
+
const disjunctions = state.formulas.filter((f) => f.kind === 'or' && f.args?.[0] && f.args?.[1]);
|
|
1595
1802
|
for (const disj of disjunctions) {
|
|
1596
1803
|
const left = disj.args?.[0];
|
|
1597
1804
|
const right = disj.args?.[1];
|
|
@@ -1720,10 +1927,113 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
1720
1927
|
subproofs: [subProofL, subProofR],
|
|
1721
1928
|
source: 'rule',
|
|
1722
1929
|
});
|
|
1723
|
-
return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
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
|
+
}
|
|
1727
2037
|
}
|
|
1728
2038
|
}
|
|
1729
2039
|
// Fallback: verificar semánticamente
|
|
@@ -1796,13 +2106,19 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
|
|
|
1796
2106
|
state.known.set(goalHash, goal);
|
|
1797
2107
|
}
|
|
1798
2108
|
const relevantSteps = traceBack(state.steps, goal);
|
|
1799
|
-
return buildProof(goal, relevantSteps, premiseNames, theory, 'semantic');
|
|
2109
|
+
return buildProof(goal, relevantSteps, premiseNames, theory, 'semantic', undefined, buildDerivationMetadata(state, relevantSteps, true));
|
|
1800
2110
|
}
|
|
1801
2111
|
}
|
|
1802
2112
|
return null;
|
|
1803
2113
|
}
|
|
1804
|
-
function findStep(
|
|
2114
|
+
function findStep(stateOrSteps, formula) {
|
|
1805
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;
|
|
1806
2122
|
for (const s of steps) {
|
|
1807
2123
|
if (formulaHash(s.formula) === hash)
|
|
1808
2124
|
return s.stepNumber;
|
|
@@ -2188,13 +2504,23 @@ class ClassicalPropositional {
|
|
|
2188
2504
|
: `${formulaToString(goal)} derivado exitosamente`,
|
|
2189
2505
|
proof,
|
|
2190
2506
|
reasoningType,
|
|
2191
|
-
reasoningSchema: rulesUsed.has('
|
|
2192
|
-
? 'φ
|
|
2193
|
-
: rulesUsed.has('
|
|
2194
|
-
? '
|
|
2195
|
-
: rulesUsed.has('
|
|
2196
|
-
? '
|
|
2197
|
-
:
|
|
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,
|
|
2198
2524
|
educationalNote: (0, educational_notes_1.pickEducationalNote)({
|
|
2199
2525
|
op: 'derive',
|
|
2200
2526
|
ok: true,
|