@stevenvo780/st-lang 3.1.1 → 3.1.3

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.
Files changed (91) hide show
  1. package/README.md +3 -3
  2. package/dist/cli/index.js +6 -11
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/lexer/lexer.d.ts.map +1 -1
  5. package/dist/lexer/lexer.js +8 -0
  6. package/dist/lexer/lexer.js.map +1 -1
  7. package/dist/lexer/tokens.d.ts +2 -0
  8. package/dist/lexer/tokens.d.ts.map +1 -1
  9. package/dist/lexer/tokens.js +6 -0
  10. package/dist/lexer/tokens.js.map +1 -1
  11. package/dist/parser/parser.d.ts.map +1 -1
  12. package/dist/parser/parser.js +40 -6
  13. package/dist/parser/parser.js.map +1 -1
  14. package/dist/profiles/aristotelian/syllogistic.d.ts +1 -1
  15. package/dist/profiles/aristotelian/syllogistic.d.ts.map +1 -1
  16. package/dist/profiles/aristotelian/syllogistic.js +26 -8
  17. package/dist/profiles/aristotelian/syllogistic.js.map +1 -1
  18. package/dist/profiles/arithmetic/index.d.ts +1 -1
  19. package/dist/profiles/arithmetic/index.d.ts.map +1 -1
  20. package/dist/profiles/arithmetic/index.js +29 -7
  21. package/dist/profiles/arithmetic/index.js.map +1 -1
  22. package/dist/profiles/classical/first-order.d.ts +1 -1
  23. package/dist/profiles/classical/first-order.d.ts.map +1 -1
  24. package/dist/profiles/classical/first-order.js +21 -3
  25. package/dist/profiles/classical/first-order.js.map +1 -1
  26. package/dist/profiles/classical/propositional.d.ts +1 -1
  27. package/dist/profiles/classical/propositional.d.ts.map +1 -1
  28. package/dist/profiles/classical/propositional.js +205 -53
  29. package/dist/profiles/classical/propositional.js.map +1 -1
  30. package/dist/profiles/intuitionistic/propositional.d.ts +1 -1
  31. package/dist/profiles/intuitionistic/propositional.d.ts.map +1 -1
  32. package/dist/profiles/intuitionistic/propositional.js +54 -7
  33. package/dist/profiles/intuitionistic/propositional.js.map +1 -1
  34. package/dist/profiles/paraconsistent/belnap.d.ts +1 -2
  35. package/dist/profiles/paraconsistent/belnap.d.ts.map +1 -1
  36. package/dist/profiles/paraconsistent/belnap.js +26 -11
  37. package/dist/profiles/paraconsistent/belnap.js.map +1 -1
  38. package/dist/profiles/probabilistic/basic.d.ts +1 -1
  39. package/dist/profiles/probabilistic/basic.d.ts.map +1 -1
  40. package/dist/profiles/probabilistic/basic.js +30 -5
  41. package/dist/profiles/probabilistic/basic.js.map +1 -1
  42. package/dist/profiles/shared/base-profile.d.ts +1 -1
  43. package/dist/profiles/shared/base-profile.d.ts.map +1 -1
  44. package/dist/profiles/shared/base-profile.js +21 -3
  45. package/dist/profiles/shared/base-profile.js.map +1 -1
  46. package/dist/profiles/shared/tableau-engine.d.ts +6 -0
  47. package/dist/profiles/shared/tableau-engine.d.ts.map +1 -1
  48. package/dist/profiles/shared/tableau-engine.js +39 -6
  49. package/dist/profiles/shared/tableau-engine.js.map +1 -1
  50. package/dist/profiles/temporal/ltl.d.ts +2 -1
  51. package/dist/profiles/temporal/ltl.d.ts.map +1 -1
  52. package/dist/profiles/temporal/ltl.js +5 -1
  53. package/dist/profiles/temporal/ltl.js.map +1 -1
  54. package/dist/protocol/handler.d.ts +0 -2
  55. package/dist/protocol/handler.d.ts.map +1 -1
  56. package/dist/protocol/handler.js +2 -6
  57. package/dist/protocol/handler.js.map +1 -1
  58. package/dist/repl/repl.d.ts.map +1 -1
  59. package/dist/repl/repl.js +5 -1
  60. package/dist/repl/repl.js.map +1 -1
  61. package/dist/runtime/compat.d.ts.map +1 -1
  62. package/dist/runtime/compat.js +2 -4
  63. package/dist/runtime/compat.js.map +1 -1
  64. package/dist/runtime/interpreter.d.ts +8 -0
  65. package/dist/runtime/interpreter.d.ts.map +1 -1
  66. package/dist/runtime/interpreter.js +194 -52
  67. package/dist/runtime/interpreter.js.map +1 -1
  68. package/dist/runtime/known-theorems.d.ts.map +1 -1
  69. package/dist/runtime/known-theorems.js +17 -5
  70. package/dist/runtime/known-theorems.js.map +1 -1
  71. package/dist/tests/cli.test.js +5 -1
  72. package/dist/tests/cli.test.js.map +1 -1
  73. package/dist/tests/core.test.js +4 -1
  74. package/dist/tests/core.test.js.map +1 -1
  75. package/dist/tests/parser.test.js +10 -0
  76. package/dist/tests/parser.test.js.map +1 -1
  77. package/dist/tests/profiles.test.js +16 -0
  78. package/dist/tests/profiles.test.js.map +1 -1
  79. package/dist/tests/protocol-text-layer.test.js +18 -0
  80. package/dist/tests/protocol-text-layer.test.js.map +1 -1
  81. package/dist/tests/regressions.test.d.ts +2 -0
  82. package/dist/tests/regressions.test.d.ts.map +1 -0
  83. package/dist/tests/regressions.test.js +167 -0
  84. package/dist/tests/regressions.test.js.map +1 -0
  85. package/dist/tests/stress-exhaustive.test.js +5 -1
  86. package/dist/tests/stress-exhaustive.test.js.map +1 -1
  87. package/dist/types/index.d.ts +10 -2
  88. package/dist/types/index.d.ts.map +1 -1
  89. package/dist/types/index.js +36 -1
  90. package/dist/types/index.js.map +1 -1
  91. package/package.json +1 -3
@@ -38,6 +38,10 @@ function computeCollectAtoms(f) {
38
38
  }
39
39
  function evaluateClassical(f, v) {
40
40
  switch (f.kind) {
41
+ case 'true':
42
+ return true;
43
+ case 'false':
44
+ return false;
41
45
  case 'atom':
42
46
  return f.name ? (v[f.name] ?? false) : false;
43
47
  case 'not':
@@ -106,11 +110,14 @@ function* generateValuationsLazy(atoms) {
106
110
  yield {};
107
111
  return;
108
112
  }
109
- const total = 1 << n;
113
+ if (n > 23)
114
+ throw new Error('Demasiadas variables para tabla de verdad (>23)');
115
+ const total = 2 ** n;
110
116
  for (let i = 0; i < total; i++) {
111
117
  const v = {};
112
118
  for (let j = 0; j < n; j++) {
113
- v[atoms[j]] = Boolean((i >> (n - 1 - j)) & 1);
119
+ const divisor = 2 ** (n - 1 - j);
120
+ v[atoms[j]] = Math.floor(i / divisor) % 2 === 1;
114
121
  }
115
122
  yield v;
116
123
  }
@@ -311,6 +318,10 @@ function formulaToString(f) {
311
318
  }
312
319
  function computeFormulaToString(f) {
313
320
  switch (f.kind) {
321
+ case 'true':
322
+ return '⊤';
323
+ case 'false':
324
+ return '⊥';
314
325
  case 'atom':
315
326
  return f.name || '?';
316
327
  case 'not': {
@@ -425,6 +436,8 @@ function computeNNF(f) {
425
436
  const args = node.args || [];
426
437
  if (!negated) {
427
438
  switch (k) {
439
+ case 'true':
440
+ case 'false':
428
441
  case 'atom':
429
442
  case 'predicate':
430
443
  return node;
@@ -468,6 +481,10 @@ function computeNNF(f) {
468
481
  }
469
482
  else {
470
483
  switch (k) {
484
+ case 'true':
485
+ return { kind: 'false' };
486
+ case 'false':
487
+ return { kind: 'true' };
471
488
  case 'atom':
472
489
  case 'predicate':
473
490
  return { kind: 'not', args: [node] };
@@ -637,18 +654,105 @@ function getSubFormulas(f) {
637
654
  // Remove atoms and the full formula itself
638
655
  return result.filter((n) => n.kind !== 'atom' && formulaToString(n) !== formulaToString(f));
639
656
  }
657
+ /**
658
+ * Igualdad estructural con alpha-equivalencia sobre variables cuantificadas.
659
+ * Cubre átomos, predicados, cuantificadores (∀/∃), modales y constantes.
660
+ */
640
661
  function formulasEqual(a, b) {
662
+ return alphaEqualFormulas(a, b, new Map(), new Map());
663
+ }
664
+ function alphaEqualFormulas(a, b, bindA, bindB, depth = 0) {
641
665
  if (a.kind !== b.kind)
642
666
  return false;
643
- if (a.kind === 'atom' && b.kind === 'atom')
644
- return a.name === b.name;
645
- if (a.args && b.args) {
646
- if (a.args.length !== b.args.length)
647
- return false;
648
- const bArgs = b.args;
649
- return a.args.every((arg, i) => formulasEqual(arg, bArgs[i]));
667
+ switch (a.kind) {
668
+ case 'true':
669
+ case 'false':
670
+ return true;
671
+ case 'atom': {
672
+ const nameA = a.name;
673
+ const nameB = b.name;
674
+ if (nameA === undefined || nameB === undefined)
675
+ return nameA === nameB;
676
+ const bA = bindA.get(nameA);
677
+ const bB = bindB.get(nameB);
678
+ if (bA !== undefined || bB !== undefined)
679
+ return bA === bB;
680
+ return nameA === nameB;
681
+ }
682
+ case 'number':
683
+ return a.value === b.value;
684
+ case 'predicate': {
685
+ if (a.name !== b.name)
686
+ return false;
687
+ const paramsA = a.params || a.terms || [];
688
+ const paramsB = b.params || b.terms || [];
689
+ if (paramsA.length !== paramsB.length)
690
+ return false;
691
+ for (let i = 0; i < paramsA.length; i++) {
692
+ const pA = paramsA[i];
693
+ const pB = paramsB[i];
694
+ const bndA = bindA.get(pA);
695
+ const bndB = bindB.get(pB);
696
+ if (bndA !== undefined || bndB !== undefined) {
697
+ if (bndA !== bndB)
698
+ return false;
699
+ }
700
+ else if (pA !== pB) {
701
+ return false;
702
+ }
703
+ }
704
+ return true;
705
+ }
706
+ case 'forall':
707
+ case 'exists': {
708
+ const vA = a.variable;
709
+ const vB = b.variable;
710
+ if (!vA || !vB)
711
+ return vA === vB;
712
+ const innerA = a.args?.[0];
713
+ const innerB = b.args?.[0];
714
+ if (!innerA || !innerB)
715
+ return false;
716
+ const prevA = bindA.get(vA);
717
+ const prevB = bindB.get(vB);
718
+ bindA.set(vA, depth);
719
+ bindB.set(vB, depth);
720
+ const eq = alphaEqualFormulas(innerA, innerB, bindA, bindB, depth + 1);
721
+ if (prevA === undefined)
722
+ bindA.delete(vA);
723
+ else
724
+ bindA.set(vA, prevA);
725
+ if (prevB === undefined)
726
+ bindB.delete(vB);
727
+ else
728
+ bindB.set(vB, prevB);
729
+ return eq;
730
+ }
731
+ case 'modal_necessity':
732
+ case 'modal_possibility':
733
+ case 'temporal_next':
734
+ case 'temporal_until': {
735
+ if (a.name !== b.name)
736
+ return false;
737
+ const argsA = a.args || [];
738
+ const argsB = b.args || [];
739
+ if (argsA.length !== argsB.length)
740
+ return false;
741
+ return argsA.every((arg, i) => alphaEqualFormulas(arg, argsB[i], bindA, bindB, depth));
742
+ }
743
+ default: {
744
+ const argsA = a.args || [];
745
+ const argsB = b.args || [];
746
+ if (argsA.length !== argsB.length)
747
+ return false;
748
+ if (argsA.length === 0) {
749
+ if (a.name !== b.name)
750
+ return false;
751
+ return a.value === b.value;
752
+ }
753
+ return argsA.every((arg, i) => alphaEqualFormulas(arg, argsB[i], bindA, bindB, depth));
754
+ }
650
755
  }
651
- return false;
652
756
  }
653
757
  // --- Motor de derivación ---
654
758
  /** Límite duro de fórmulas derivadas para evitar explosión combinatoria */
@@ -690,7 +794,7 @@ function isRelevantToGoal(f, goal) {
690
794
  };
691
795
  return checkSub(goal);
692
796
  }
693
- function addDerivedFormula(state, formula, justification, premises) {
797
+ function addDerivedFormula(state, formula, justification, premises, source = 'rule') {
694
798
  const hash = formulaHash(formula);
695
799
  if (state.known.has(hash))
696
800
  return false;
@@ -700,6 +804,7 @@ function addDerivedFormula(state, formula, justification, premises) {
700
804
  formula,
701
805
  justification,
702
806
  premises,
807
+ source,
703
808
  });
704
809
  state.known.set(hash, formula);
705
810
  return true;
@@ -809,6 +914,7 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
809
914
  formula: f,
810
915
  justification: `Premisa (${name})`,
811
916
  premises: [],
917
+ source: 'premise',
812
918
  });
813
919
  state.known.set(formulaHash(f), f);
814
920
  }
@@ -1423,14 +1529,14 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
1423
1529
  const subProof = tryDerive(subGoal, tempTheory, subPremises, depth + 1);
1424
1530
  if (subProof && subProof.status === 'complete') {
1425
1531
  // Check the sub-proof doesn't rely solely on semantic fallback
1426
- const isSyntactic = subProof.steps.every((s) => !s.justification.startsWith('Verificacion semantica'));
1532
+ const isSyntactic = subProof.steps.every((s) => s.source !== 'semantic');
1427
1533
  if (isSyntactic) {
1428
1534
  // Build the main proof: premises + sub-derivation steps + conditional proof conclusion
1429
1535
  const mainSteps = [];
1430
1536
  let stepNum = 0;
1431
1537
  // Copy premise steps from current state
1432
1538
  for (const s of state.steps) {
1433
- if (s.justification.startsWith('Premisa')) {
1539
+ if (s.source === 'premise') {
1434
1540
  stepNum++;
1435
1541
  mainSteps.push({ ...s, stepNumber: stepNum, premises: [] });
1436
1542
  }
@@ -1443,17 +1549,18 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
1443
1549
  formula: assumption,
1444
1550
  justification: 'Supuesto (para prueba condicional)',
1445
1551
  premises: [],
1552
+ source: 'assumption',
1446
1553
  });
1447
1554
  // Add sub-derivation steps (renumber, adjusting premise references)
1448
1555
  const subStepMap = new Map();
1449
1556
  for (const s of subProof.steps) {
1450
- if (s.justification.startsWith('Premisa') && formulasEqual(s.formula, assumption)) {
1557
+ if (s.source === 'premise' && formulasEqual(s.formula, assumption)) {
1451
1558
  subStepMap.set(s.stepNumber, assumptionStepNum);
1452
1559
  continue;
1453
1560
  }
1454
- if (s.justification.startsWith('Premisa')) {
1561
+ if (s.source === 'premise') {
1455
1562
  // Find existing premise step in main
1456
- const existing = mainSteps.find((ms) => ms.justification.startsWith('Premisa') && formulasEqual(ms.formula, s.formula));
1563
+ const existing = mainSteps.find((ms) => ms.source === 'premise' && formulasEqual(ms.formula, s.formula));
1457
1564
  if (existing) {
1458
1565
  subStepMap.set(s.stepNumber, existing.stepNumber);
1459
1566
  continue;
@@ -1466,6 +1573,7 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
1466
1573
  formula: s.formula,
1467
1574
  justification: s.justification,
1468
1575
  premises: s.premises.map((p) => subStepMap.get(p) || p),
1576
+ source: s.source,
1469
1577
  });
1470
1578
  }
1471
1579
  // Add final conditional proof step
@@ -1477,6 +1585,7 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
1477
1585
  justification: 'Prueba Condicional (Teorema de Deduccion)',
1478
1586
  premises: [assumptionStepNum, subGoalStepNum],
1479
1587
  subproofs: [subProof],
1588
+ source: 'rule',
1480
1589
  });
1481
1590
  return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [subProof]);
1482
1591
  }
@@ -1505,7 +1614,7 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
1505
1614
  const subProofL = tryDerive(goal, tempTheoryL, subPremisesL, depth + 1);
1506
1615
  if (!subProofL || subProofL.status !== 'complete')
1507
1616
  continue;
1508
- const isSyntacticL = subProofL.steps.every((s) => !s.justification.startsWith('Verificacion semantica'));
1617
+ const isSyntacticL = subProofL.steps.every((s) => s.source !== 'semantic');
1509
1618
  if (!isSyntacticL)
1510
1619
  continue;
1511
1620
  // Try to derive goal assuming right
@@ -1522,7 +1631,7 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
1522
1631
  const subProofR = tryDerive(goal, tempTheoryR, subPremisesR, depth + 1);
1523
1632
  if (!subProofR || subProofR.status !== 'complete')
1524
1633
  continue;
1525
- const isSyntacticR = subProofR.steps.every((s) => !s.justification.startsWith('Verificacion semantica'));
1634
+ const isSyntacticR = subProofR.steps.every((s) => s.source !== 'semantic');
1526
1635
  if (!isSyntacticR)
1527
1636
  continue;
1528
1637
  // Both cases succeed — build proof by cases
@@ -1530,7 +1639,7 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
1530
1639
  let stepNum = 0;
1531
1640
  // Copy premise steps
1532
1641
  for (const s of state.steps) {
1533
- if (s.justification.startsWith('Premisa')) {
1642
+ if (s.source === 'premise') {
1534
1643
  stepNum++;
1535
1644
  mainSteps.push({ ...s, stepNumber: stepNum, premises: [] });
1536
1645
  }
@@ -1544,15 +1653,16 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
1544
1653
  formula: left,
1545
1654
  justification: 'Supuesto (caso izquierdo)',
1546
1655
  premises: [],
1656
+ source: 'assumption',
1547
1657
  });
1548
1658
  const leftStepMap = new Map();
1549
1659
  for (const s of subProofL.steps) {
1550
- if (s.justification.startsWith('Premisa') && formulasEqual(s.formula, left)) {
1660
+ if (s.source === 'premise' && formulasEqual(s.formula, left)) {
1551
1661
  leftStepMap.set(s.stepNumber, leftAssumptionStep);
1552
1662
  continue;
1553
1663
  }
1554
- if (s.justification.startsWith('Premisa')) {
1555
- const existing = mainSteps.find((ms) => ms.justification.startsWith('Premisa') && formulasEqual(ms.formula, s.formula));
1664
+ if (s.source === 'premise') {
1665
+ const existing = mainSteps.find((ms) => ms.source === 'premise' && formulasEqual(ms.formula, s.formula));
1556
1666
  if (existing) {
1557
1667
  leftStepMap.set(s.stepNumber, existing.stepNumber);
1558
1668
  continue;
@@ -1565,6 +1675,7 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
1565
1675
  formula: s.formula,
1566
1676
  justification: s.justification,
1567
1677
  premises: s.premises.map((p) => leftStepMap.get(p) || p),
1678
+ source: s.source,
1568
1679
  });
1569
1680
  }
1570
1681
  const leftGoalStep = leftStepMap.get(subProofL.steps[subProofL.steps.length - 1]?.stepNumber ?? 0) ?? stepNum;
@@ -1576,15 +1687,16 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
1576
1687
  formula: right,
1577
1688
  justification: 'Supuesto (caso derecho)',
1578
1689
  premises: [],
1690
+ source: 'assumption',
1579
1691
  });
1580
1692
  const rightStepMap = new Map();
1581
1693
  for (const s of subProofR.steps) {
1582
- if (s.justification.startsWith('Premisa') && formulasEqual(s.formula, right)) {
1694
+ if (s.source === 'premise' && formulasEqual(s.formula, right)) {
1583
1695
  rightStepMap.set(s.stepNumber, rightAssumptionStep);
1584
1696
  continue;
1585
1697
  }
1586
- if (s.justification.startsWith('Premisa')) {
1587
- const existing = mainSteps.find((ms) => ms.justification.startsWith('Premisa') && formulasEqual(ms.formula, s.formula));
1698
+ if (s.source === 'premise') {
1699
+ const existing = mainSteps.find((ms) => ms.source === 'premise' && formulasEqual(ms.formula, s.formula));
1588
1700
  if (existing) {
1589
1701
  rightStepMap.set(s.stepNumber, existing.stepNumber);
1590
1702
  continue;
@@ -1597,6 +1709,7 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
1597
1709
  formula: s.formula,
1598
1710
  justification: s.justification,
1599
1711
  premises: s.premises.map((p) => rightStepMap.get(p) || p),
1712
+ source: s.source,
1600
1713
  });
1601
1714
  }
1602
1715
  const rightGoalStep = rightStepMap.get(subProofR.steps[subProofR.steps.length - 1]?.stepNumber ?? 0) ?? stepNum;
@@ -1608,6 +1721,7 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
1608
1721
  justification: 'Eliminacion de disyuncion (prueba por casos)',
1609
1722
  premises: [disjStepNum, leftGoalStep, rightGoalStep],
1610
1723
  subproofs: [subProofL, subProofR],
1724
+ source: 'rule',
1611
1725
  });
1612
1726
  return buildProof(goal, mainSteps, premiseNames, theory, 'natural_deduction', [
1613
1727
  subProofL,
@@ -1680,6 +1794,7 @@ function tryDerive(goal, theory, premiseNames, depth = 0) {
1680
1794
  formula: goal,
1681
1795
  justification: 'Verificacion semantica (todas las valuaciones satisfacen la consecuencia)',
1682
1796
  premises: premiseStepNums,
1797
+ source: 'semantic',
1683
1798
  });
1684
1799
  state.known.set(goalHash, goal);
1685
1800
  }
@@ -1904,26 +2019,56 @@ class ClassicalPropositional {
1904
2019
  };
1905
2020
  }
1906
2021
  }
1907
- prove(goal, theory) {
2022
+ prove(goal, theory, premises) {
1908
2023
  const wf = this.checkWellFormed(goal);
1909
2024
  if (wf.length > 0) {
1910
2025
  return { status: 'error', diagnostics: wf, formula: goal };
1911
2026
  }
1912
- const premiseNames = Array.from(theory.axioms.keys());
1913
- const proof = tryDerive(goal, theory, premiseNames);
2027
+ const usingRestricted = premises !== undefined && premises.length > 0;
2028
+ const premiseNames = usingRestricted
2029
+ ? premises.filter((n) => theory.axioms.has(n) || theory.theorems.has(n))
2030
+ : Array.from(theory.axioms.keys());
2031
+ const diagnostics = [];
2032
+ if (usingRestricted) {
2033
+ for (const n of premises) {
2034
+ if (!theory.axioms.has(n) && !theory.theorems.has(n)) {
2035
+ diagnostics.push({
2036
+ severity: 'warning',
2037
+ message: `Premisa '${n}' no encontrada en la teoría; será ignorada en prove`,
2038
+ });
2039
+ }
2040
+ }
2041
+ }
2042
+ const effectiveTheory = usingRestricted
2043
+ ? {
2044
+ profile: theory.profile,
2045
+ axioms: new Map(premiseNames
2046
+ .filter((n) => theory.axioms.has(n))
2047
+ .map((n) => [n, theory.axioms.get(n)])),
2048
+ theorems: new Map(premiseNames
2049
+ .filter((n) => theory.theorems.has(n))
2050
+ .map((n) => [n, theory.theorems.get(n)])),
2051
+ claims: theory.claims,
2052
+ judgments: theory.judgments,
2053
+ }
2054
+ : theory;
2055
+ const proof = tryDerive(goal, effectiveTheory, premiseNames);
1914
2056
  if (proof && proof.status === 'complete') {
2057
+ const isSemantic = proof.method === 'semantic';
1915
2058
  return {
1916
2059
  status: 'provable',
1917
- output: `${formulaToString(goal)} es DEMOSTRABLE desde la teoria`,
2060
+ output: isSemantic
2061
+ ? `${formulaToString(goal)} es DEMOSTRABLE desde la teoria (verificación semántica, sin derivación sintáctica)`
2062
+ : `${formulaToString(goal)} es DEMOSTRABLE desde la teoria`,
1918
2063
  proof,
1919
2064
  educationalNote: (0, educational_notes_1.pickEducationalNote)({ op: 'prove', ok: true }),
1920
- diagnostics: [],
2065
+ diagnostics,
1921
2066
  formula: goal,
1922
2067
  };
1923
2068
  }
1924
2069
  // Semantic fallback: verify via SAT/truth-table whether goal follows from axioms
1925
2070
  const allAxiomFormulas = premiseNames
1926
- .map((n) => theory.axioms.get(n) || theory.theorems.get(n))
2071
+ .map((n) => effectiveTheory.axioms.get(n) || effectiveTheory.theorems.get(n))
1927
2072
  .filter((f) => f !== undefined);
1928
2073
  let semanticResult;
1929
2074
  const atoms = new Set();
@@ -1980,42 +2125,46 @@ class ClassicalPropositional {
1980
2125
  }
1981
2126
  }
1982
2127
  if (semanticResult) {
2128
+ const premiseSteps = [];
2129
+ premiseNames.forEach((n, i) => {
2130
+ const f = effectiveTheory.axioms.get(n) || effectiveTheory.theorems.get(n);
2131
+ if (f) {
2132
+ premiseSteps.push({
2133
+ stepNumber: i + 1,
2134
+ formula: f,
2135
+ justification: `Premisa (${n})`,
2136
+ premises: [],
2137
+ source: 'premise',
2138
+ });
2139
+ }
2140
+ });
1983
2141
  const semanticProofSteps = [
1984
- ...premiseNames
1985
- .map((n, i) => {
1986
- const f = theory.axioms.get(n) || theory.theorems.get(n);
1987
- return f
1988
- ? {
1989
- stepNumber: i + 1,
1990
- formula: f,
1991
- justification: `Premisa (${n})`,
1992
- premises: [],
1993
- }
1994
- : null;
1995
- })
1996
- .filter((s) => s !== null),
2142
+ ...premiseSteps,
1997
2143
  {
1998
2144
  stepNumber: premiseNames.length + 1,
1999
2145
  formula: goal,
2000
2146
  justification: 'Verificacion semantica (tautologia o consecuencia logica)',
2001
2147
  premises: premiseNames.map((_, i) => i + 1),
2148
+ source: 'semantic',
2002
2149
  },
2003
2150
  ];
2004
- const semanticProof = buildProof(goal, semanticProofSteps, premiseNames, theory, 'semantic');
2151
+ const semanticProof = buildProof(goal, semanticProofSteps, premiseNames, effectiveTheory, 'semantic');
2005
2152
  return {
2006
2153
  status: 'provable',
2007
- output: `${formulaToString(goal)} es DEMOSTRABLE desde la teoria`,
2154
+ output: `${formulaToString(goal)} es DEMOSTRABLE desde la teoria (verificación semántica, sin derivación sintáctica)`,
2008
2155
  proof: semanticProof,
2009
2156
  educationalNote: (0, educational_notes_1.pickEducationalNote)({ op: 'prove', ok: true }),
2010
- diagnostics: [],
2157
+ diagnostics,
2011
2158
  formula: goal,
2012
2159
  };
2013
2160
  }
2161
+ // Ni derivación sintáctica ni consecuencia semántica: existe contramodelo.
2162
+ // Esto sí es refutable en el sentido fuerte.
2014
2163
  return {
2015
2164
  status: 'refutable',
2016
- output: `${formulaToString(goal)} NO es demostrable desde la teoria dada`,
2165
+ output: `${formulaToString(goal)} NO se sigue de la teoría (existe contramodelo en ${formulaToString(goal)})`,
2017
2166
  educationalNote: (0, educational_notes_1.pickEducationalNote)({ op: 'prove', ok: false }),
2018
- diagnostics: [],
2167
+ diagnostics,
2019
2168
  formula: goal,
2020
2169
  };
2021
2170
  }
@@ -2029,14 +2178,17 @@ class ClassicalPropositional {
2029
2178
  // Build reasoning info
2030
2179
  const rulesUsed = new Set();
2031
2180
  for (const step of proof.steps) {
2032
- if (!step.justification.startsWith('Premisa')) {
2181
+ if (step.source !== 'premise') {
2033
2182
  rulesUsed.add(step.justification);
2034
2183
  }
2035
2184
  }
2036
2185
  const reasoningType = rulesUsed.size > 0 ? Array.from(rulesUsed).join(', ') : 'Derivación directa';
2186
+ const isSemantic = proof.method === 'semantic';
2037
2187
  return {
2038
2188
  status: 'provable',
2039
- output: `${formulaToString(goal)} derivado exitosamente`,
2189
+ output: isSemantic
2190
+ ? `${formulaToString(goal)} derivado (verificación semántica, sin derivación sintáctica)`
2191
+ : `${formulaToString(goal)} derivado exitosamente`,
2040
2192
  proof,
2041
2193
  reasoningType,
2042
2194
  reasoningSchema: rulesUsed.has('Modus Ponens')
@@ -2057,8 +2209,8 @@ class ClassicalPropositional {
2057
2209
  };
2058
2210
  }
2059
2211
  return {
2060
- status: 'refutable',
2061
- output: `No se puede derivar ${formulaToString(goal)} desde las premisas dadas`,
2212
+ status: 'unknown',
2213
+ output: `No se pudo derivar ${formulaToString(goal)} desde las premisas dadas (sin refutación)`,
2062
2214
  educationalNote: (0, educational_notes_1.pickEducationalNote)({ op: 'derive', ok: false }),
2063
2215
  diagnostics: [],
2064
2216
  formula: goal,