@stevenvo780/st-lang 4.9.0 → 4.11.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.
Files changed (241) hide show
  1. package/dist/logic/profiles/natural-deduction-nk/formula.d.ts +18 -0
  2. package/dist/logic/profiles/natural-deduction-nk/formula.d.ts.map +1 -0
  3. package/dist/logic/profiles/natural-deduction-nk/formula.js +102 -0
  4. package/dist/logic/profiles/natural-deduction-nk/formula.js.map +1 -0
  5. package/dist/logic/profiles/natural-deduction-nk/index.d.ts +5 -0
  6. package/dist/logic/profiles/natural-deduction-nk/index.d.ts.map +1 -0
  7. package/dist/logic/profiles/natural-deduction-nk/index.js +28 -0
  8. package/dist/logic/profiles/natural-deduction-nk/index.js.map +1 -0
  9. package/dist/logic/profiles/natural-deduction-nk/prover.d.ts +49 -0
  10. package/dist/logic/profiles/natural-deduction-nk/prover.d.ts.map +1 -0
  11. package/dist/logic/profiles/natural-deduction-nk/prover.js +557 -0
  12. package/dist/logic/profiles/natural-deduction-nk/prover.js.map +1 -0
  13. package/dist/logic/profiles/natural-deduction-nk/types.d.ts +48 -0
  14. package/dist/logic/profiles/natural-deduction-nk/types.d.ts.map +1 -0
  15. package/dist/logic/profiles/natural-deduction-nk/types.js +35 -0
  16. package/dist/logic/profiles/natural-deduction-nk/types.js.map +1 -0
  17. package/dist/proof-systems/distributed-exchange/index.d.ts +101 -0
  18. package/dist/proof-systems/distributed-exchange/index.d.ts.map +1 -0
  19. package/dist/proof-systems/distributed-exchange/index.js +408 -0
  20. package/dist/proof-systems/distributed-exchange/index.js.map +1 -0
  21. package/dist/reasoning/automata/dfa.d.ts +17 -0
  22. package/dist/reasoning/automata/dfa.d.ts.map +1 -0
  23. package/dist/reasoning/automata/dfa.js +276 -0
  24. package/dist/reasoning/automata/dfa.js.map +1 -0
  25. package/dist/reasoning/automata/index.d.ts +8 -0
  26. package/dist/reasoning/automata/index.d.ts.map +1 -0
  27. package/dist/reasoning/automata/index.js +64 -0
  28. package/dist/reasoning/automata/index.js.map +1 -0
  29. package/dist/reasoning/automata/languages.d.ts +10 -0
  30. package/dist/reasoning/automata/languages.d.ts.map +1 -0
  31. package/dist/reasoning/automata/languages.js +78 -0
  32. package/dist/reasoning/automata/languages.js.map +1 -0
  33. package/dist/reasoning/automata/nfa.d.ts +8 -0
  34. package/dist/reasoning/automata/nfa.d.ts.map +1 -0
  35. package/dist/reasoning/automata/nfa.js +122 -0
  36. package/dist/reasoning/automata/nfa.js.map +1 -0
  37. package/dist/reasoning/automata/pda.d.ts +10 -0
  38. package/dist/reasoning/automata/pda.d.ts.map +1 -0
  39. package/dist/reasoning/automata/pda.js +169 -0
  40. package/dist/reasoning/automata/pda.js.map +1 -0
  41. package/dist/reasoning/automata/regex.d.ts +6 -0
  42. package/dist/reasoning/automata/regex.d.ts.map +1 -0
  43. package/dist/reasoning/automata/regex.js +259 -0
  44. package/dist/reasoning/automata/regex.js.map +1 -0
  45. package/dist/reasoning/automata/types.d.ts +69 -0
  46. package/dist/reasoning/automata/types.d.ts.map +1 -0
  47. package/dist/reasoning/automata/types.js +29 -0
  48. package/dist/reasoning/automata/types.js.map +1 -0
  49. package/dist/reasoning/computability/index.d.ts +239 -0
  50. package/dist/reasoning/computability/index.d.ts.map +1 -0
  51. package/dist/reasoning/computability/index.js +851 -0
  52. package/dist/reasoning/computability/index.js.map +1 -0
  53. package/dist/reasoning/graph-theory/index.d.ts +63 -0
  54. package/dist/reasoning/graph-theory/index.d.ts.map +1 -0
  55. package/dist/reasoning/graph-theory/index.js +1043 -0
  56. package/dist/reasoning/graph-theory/index.js.map +1 -0
  57. package/dist/reasoning/group-presentation/cayley.d.ts +8 -0
  58. package/dist/reasoning/group-presentation/cayley.d.ts.map +1 -0
  59. package/dist/reasoning/group-presentation/cayley.js +38 -0
  60. package/dist/reasoning/group-presentation/cayley.js.map +1 -0
  61. package/dist/reasoning/group-presentation/index.d.ts +8 -0
  62. package/dist/reasoning/group-presentation/index.d.ts.map +1 -0
  63. package/dist/reasoning/group-presentation/index.js +36 -0
  64. package/dist/reasoning/group-presentation/index.js.map +1 -0
  65. package/dist/reasoning/group-presentation/standard-groups.d.ts +6 -0
  66. package/dist/reasoning/group-presentation/standard-groups.d.ts.map +1 -0
  67. package/dist/reasoning/group-presentation/standard-groups.js +93 -0
  68. package/dist/reasoning/group-presentation/standard-groups.js.map +1 -0
  69. package/dist/reasoning/group-presentation/todd-coxeter.d.ts +10 -0
  70. package/dist/reasoning/group-presentation/todd-coxeter.d.ts.map +1 -0
  71. package/dist/reasoning/group-presentation/todd-coxeter.js +362 -0
  72. package/dist/reasoning/group-presentation/todd-coxeter.js.map +1 -0
  73. package/dist/reasoning/group-presentation/types.d.ts +7 -0
  74. package/dist/reasoning/group-presentation/types.d.ts.map +1 -0
  75. package/dist/reasoning/group-presentation/types.js +22 -0
  76. package/dist/reasoning/group-presentation/types.js.map +1 -0
  77. package/dist/reasoning/group-presentation/words.d.ts +10 -0
  78. package/dist/reasoning/group-presentation/words.d.ts.map +1 -0
  79. package/dist/reasoning/group-presentation/words.js +109 -0
  80. package/dist/reasoning/group-presentation/words.js.map +1 -0
  81. package/dist/reasoning/number-theory/crt.d.ts +9 -0
  82. package/dist/reasoning/number-theory/crt.d.ts.map +1 -0
  83. package/dist/reasoning/number-theory/crt.js +39 -0
  84. package/dist/reasoning/number-theory/crt.js.map +1 -0
  85. package/dist/reasoning/number-theory/diophantine.d.ts +10 -0
  86. package/dist/reasoning/number-theory/diophantine.d.ts.map +1 -0
  87. package/dist/reasoning/number-theory/diophantine.js +87 -0
  88. package/dist/reasoning/number-theory/diophantine.js.map +1 -0
  89. package/dist/reasoning/number-theory/factorization.d.ts +12 -0
  90. package/dist/reasoning/number-theory/factorization.d.ts.map +1 -0
  91. package/dist/reasoning/number-theory/factorization.js +136 -0
  92. package/dist/reasoning/number-theory/factorization.js.map +1 -0
  93. package/dist/reasoning/number-theory/gcd.d.ts +8 -0
  94. package/dist/reasoning/number-theory/gcd.d.ts.map +1 -0
  95. package/dist/reasoning/number-theory/gcd.js +51 -0
  96. package/dist/reasoning/number-theory/gcd.js.map +1 -0
  97. package/dist/reasoning/number-theory/index.d.ts +9 -0
  98. package/dist/reasoning/number-theory/index.d.ts.map +1 -0
  99. package/dist/reasoning/number-theory/index.js +46 -0
  100. package/dist/reasoning/number-theory/index.js.map +1 -0
  101. package/dist/reasoning/number-theory/modular.d.ts +6 -0
  102. package/dist/reasoning/number-theory/modular.d.ts.map +1 -0
  103. package/dist/reasoning/number-theory/modular.js +75 -0
  104. package/dist/reasoning/number-theory/modular.js.map +1 -0
  105. package/dist/reasoning/number-theory/primality.d.ts +6 -0
  106. package/dist/reasoning/number-theory/primality.d.ts.map +1 -0
  107. package/dist/reasoning/number-theory/primality.js +144 -0
  108. package/dist/reasoning/number-theory/primality.js.map +1 -0
  109. package/dist/reasoning/number-theory/symbols.d.ts +3 -0
  110. package/dist/reasoning/number-theory/symbols.d.ts.map +1 -0
  111. package/dist/reasoning/number-theory/symbols.js +57 -0
  112. package/dist/reasoning/number-theory/symbols.js.map +1 -0
  113. package/dist/reasoning/real-analysis/index.d.ts +127 -0
  114. package/dist/reasoning/real-analysis/index.d.ts.map +1 -0
  115. package/dist/reasoning/real-analysis/index.js +638 -0
  116. package/dist/reasoning/real-analysis/index.js.map +1 -0
  117. package/dist/reasoning/topology/index.d.ts +41 -0
  118. package/dist/reasoning/topology/index.d.ts.map +1 -0
  119. package/dist/reasoning/topology/index.js +739 -0
  120. package/dist/reasoning/topology/index.js.map +1 -0
  121. package/dist/tests/logic/profiles/natural-deduction-nk/nk.test.d.ts +2 -0
  122. package/dist/tests/logic/profiles/natural-deduction-nk/nk.test.d.ts.map +1 -0
  123. package/dist/tests/logic/profiles/natural-deduction-nk/nk.test.js +288 -0
  124. package/dist/tests/logic/profiles/natural-deduction-nk/nk.test.js.map +1 -0
  125. package/dist/tests/proof-systems/distributed-exchange/distributed-exchange.test.d.ts +2 -0
  126. package/dist/tests/proof-systems/distributed-exchange/distributed-exchange.test.d.ts.map +1 -0
  127. package/dist/tests/proof-systems/distributed-exchange/distributed-exchange.test.js +328 -0
  128. package/dist/tests/proof-systems/distributed-exchange/distributed-exchange.test.js.map +1 -0
  129. package/dist/tests/reasoning/automata/automata.test.d.ts +2 -0
  130. package/dist/tests/reasoning/automata/automata.test.d.ts.map +1 -0
  131. package/dist/tests/reasoning/automata/automata.test.js +310 -0
  132. package/dist/tests/reasoning/automata/automata.test.js.map +1 -0
  133. package/dist/tests/reasoning/computability/computability.test.d.ts +2 -0
  134. package/dist/tests/reasoning/computability/computability.test.d.ts.map +1 -0
  135. package/dist/tests/reasoning/computability/computability.test.js +246 -0
  136. package/dist/tests/reasoning/computability/computability.test.js.map +1 -0
  137. package/dist/tests/reasoning/graph-theory/graph-theory.test.d.ts +2 -0
  138. package/dist/tests/reasoning/graph-theory/graph-theory.test.d.ts.map +1 -0
  139. package/dist/tests/reasoning/graph-theory/graph-theory.test.js +363 -0
  140. package/dist/tests/reasoning/graph-theory/graph-theory.test.js.map +1 -0
  141. package/dist/tests/reasoning/group-presentation/group-presentation.test.d.ts +2 -0
  142. package/dist/tests/reasoning/group-presentation/group-presentation.test.d.ts.map +1 -0
  143. package/dist/tests/reasoning/group-presentation/group-presentation.test.js +229 -0
  144. package/dist/tests/reasoning/group-presentation/group-presentation.test.js.map +1 -0
  145. package/dist/tests/reasoning/number-theory/number-theory.test.d.ts +2 -0
  146. package/dist/tests/reasoning/number-theory/number-theory.test.d.ts.map +1 -0
  147. package/dist/tests/reasoning/number-theory/number-theory.test.js +170 -0
  148. package/dist/tests/reasoning/number-theory/number-theory.test.js.map +1 -0
  149. package/dist/tests/reasoning/real-analysis/real-analysis.test.d.ts +2 -0
  150. package/dist/tests/reasoning/real-analysis/real-analysis.test.d.ts.map +1 -0
  151. package/dist/tests/reasoning/real-analysis/real-analysis.test.js +197 -0
  152. package/dist/tests/reasoning/real-analysis/real-analysis.test.js.map +1 -0
  153. package/dist/tests/reasoning/topology/topology.test.d.ts +2 -0
  154. package/dist/tests/reasoning/topology/topology.test.d.ts.map +1 -0
  155. package/dist/tests/reasoning/topology/topology.test.js +327 -0
  156. package/dist/tests/reasoning/topology/topology.test.js.map +1 -0
  157. package/dist/tests/tooling/exporters/coq-v2/coq-v2-exporter.test.d.ts +2 -0
  158. package/dist/tests/tooling/exporters/coq-v2/coq-v2-exporter.test.d.ts.map +1 -0
  159. package/dist/tests/tooling/exporters/coq-v2/coq-v2-exporter.test.js +411 -0
  160. package/dist/tests/tooling/exporters/coq-v2/coq-v2-exporter.test.js.map +1 -0
  161. package/dist/tests/tooling/exporters/lean4/lean4-exporter.test.d.ts +2 -0
  162. package/dist/tests/tooling/exporters/lean4/lean4-exporter.test.d.ts.map +1 -0
  163. package/dist/tests/tooling/exporters/lean4/lean4-exporter.test.js +473 -0
  164. package/dist/tests/tooling/exporters/lean4/lean4-exporter.test.js.map +1 -0
  165. package/dist/tests/tooling/lemma-library/lemma-library.test.d.ts +2 -0
  166. package/dist/tests/tooling/lemma-library/lemma-library.test.d.ts.map +1 -0
  167. package/dist/tests/tooling/lemma-library/lemma-library.test.js +197 -0
  168. package/dist/tests/tooling/lemma-library/lemma-library.test.js.map +1 -0
  169. package/dist/tests/tooling/provenance/ledger.test.d.ts +2 -0
  170. package/dist/tests/tooling/provenance/ledger.test.d.ts.map +1 -0
  171. package/dist/tests/tooling/provenance/ledger.test.js +545 -0
  172. package/dist/tests/tooling/provenance/ledger.test.js.map +1 -0
  173. package/dist/tooling/exporters/coq-v2/index.d.ts +68 -0
  174. package/dist/tooling/exporters/coq-v2/index.d.ts.map +1 -0
  175. package/dist/tooling/exporters/coq-v2/index.js +692 -0
  176. package/dist/tooling/exporters/coq-v2/index.js.map +1 -0
  177. package/dist/tooling/exporters/lean4/index.d.ts +47 -0
  178. package/dist/tooling/exporters/lean4/index.d.ts.map +1 -0
  179. package/dist/tooling/exporters/lean4/index.js +423 -0
  180. package/dist/tooling/exporters/lean4/index.js.map +1 -0
  181. package/dist/tooling/lemma-library/apply.d.ts +9 -0
  182. package/dist/tooling/lemma-library/apply.d.ts.map +1 -0
  183. package/dist/tooling/lemma-library/apply.js +94 -0
  184. package/dist/tooling/lemma-library/apply.js.map +1 -0
  185. package/dist/tooling/lemma-library/arithmetic.d.ts +3 -0
  186. package/dist/tooling/lemma-library/arithmetic.d.ts.map +1 -0
  187. package/dist/tooling/lemma-library/arithmetic.js +176 -0
  188. package/dist/tooling/lemma-library/arithmetic.js.map +1 -0
  189. package/dist/tooling/lemma-library/firstorder.d.ts +3 -0
  190. package/dist/tooling/lemma-library/firstorder.d.ts.map +1 -0
  191. package/dist/tooling/lemma-library/firstorder.js +136 -0
  192. package/dist/tooling/lemma-library/firstorder.js.map +1 -0
  193. package/dist/tooling/lemma-library/index.d.ts +13 -0
  194. package/dist/tooling/lemma-library/index.d.ts.map +1 -0
  195. package/dist/tooling/lemma-library/index.js +32 -0
  196. package/dist/tooling/lemma-library/index.js.map +1 -0
  197. package/dist/tooling/lemma-library/library.d.ts +34 -0
  198. package/dist/tooling/lemma-library/library.d.ts.map +1 -0
  199. package/dist/tooling/lemma-library/library.js +126 -0
  200. package/dist/tooling/lemma-library/library.js.map +1 -0
  201. package/dist/tooling/lemma-library/modal.d.ts +3 -0
  202. package/dist/tooling/lemma-library/modal.d.ts.map +1 -0
  203. package/dist/tooling/lemma-library/modal.js +138 -0
  204. package/dist/tooling/lemma-library/modal.js.map +1 -0
  205. package/dist/tooling/lemma-library/propositional.d.ts +3 -0
  206. package/dist/tooling/lemma-library/propositional.d.ts.map +1 -0
  207. package/dist/tooling/lemma-library/propositional.js +265 -0
  208. package/dist/tooling/lemma-library/propositional.js.map +1 -0
  209. package/dist/tooling/lemma-library/set-theory.d.ts +3 -0
  210. package/dist/tooling/lemma-library/set-theory.d.ts.map +1 -0
  211. package/dist/tooling/lemma-library/set-theory.js +134 -0
  212. package/dist/tooling/lemma-library/set-theory.js.map +1 -0
  213. package/dist/tooling/lemma-library/standard.d.ts +3 -0
  214. package/dist/tooling/lemma-library/standard.d.ts.map +1 -0
  215. package/dist/tooling/lemma-library/standard.js +27 -0
  216. package/dist/tooling/lemma-library/standard.js.map +1 -0
  217. package/dist/tooling/lemma-library/tfidf.d.ts +5 -0
  218. package/dist/tooling/lemma-library/tfidf.d.ts.map +1 -0
  219. package/dist/tooling/lemma-library/tfidf.js +100 -0
  220. package/dist/tooling/lemma-library/tfidf.js.map +1 -0
  221. package/dist/tooling/lemma-library/tokenize.d.ts +2 -0
  222. package/dist/tooling/lemma-library/tokenize.d.ts.map +1 -0
  223. package/dist/tooling/lemma-library/tokenize.js +74 -0
  224. package/dist/tooling/lemma-library/tokenize.js.map +1 -0
  225. package/dist/tooling/lemma-library/types.d.ts +53 -0
  226. package/dist/tooling/lemma-library/types.d.ts.map +1 -0
  227. package/dist/tooling/lemma-library/types.js +10 -0
  228. package/dist/tooling/lemma-library/types.js.map +1 -0
  229. package/dist/tooling/provenance/index.d.ts +3 -0
  230. package/dist/tooling/provenance/index.d.ts.map +1 -0
  231. package/dist/tooling/provenance/index.js +16 -0
  232. package/dist/tooling/provenance/index.js.map +1 -0
  233. package/dist/tooling/provenance/ledger.d.ts +89 -0
  234. package/dist/tooling/provenance/ledger.d.ts.map +1 -0
  235. package/dist/tooling/provenance/ledger.js +439 -0
  236. package/dist/tooling/provenance/ledger.js.map +1 -0
  237. package/dist/tooling/provenance/types.d.ts +70 -0
  238. package/dist/tooling/provenance/types.d.ts.map +1 -0
  239. package/dist/tooling/provenance/types.js +14 -0
  240. package/dist/tooling/provenance/types.js.map +1 -0
  241. package/package.json +1 -1
@@ -0,0 +1,851 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // ST Computability theory — Turing machines + undecidability
4
+ // ============================================================
5
+ // Cuatro piezas que aterrizan los resultados clásicos de Turing,
6
+ // Kleene y Rice:
7
+ //
8
+ // 1. Máquina de Turing determinista de una cinta (TM): estados,
9
+ // alfabeto de cinta, transición parcial, cabeza con movimientos
10
+ // L/R/S (stay), aceptación/rechazo por estado. Trazas y pasos
11
+ // explícitos. `run` y `trace` son simulación pura — sin efectos.
12
+ //
13
+ // 2. Halting acotado: dado un budget `maxSteps`, devolvemos
14
+ // `boolean | 'unknown'`. Esto refleja el hecho de que el problema
15
+ // de la parada es semi-decidible: si la máquina para dentro del
16
+ // budget sabemos sí/no; si no, no podemos concluir (no es lo
17
+ // mismo que "no para").
18
+ //
19
+ // 3. Funciones primitivas recursivas (PRF): cero, sucesor,
20
+ // proyección, composición y recursión primitiva. `evalPR` corre
21
+ // la semántica estándar. Constructores PR_ADD, PR_MUL, PR_POW,
22
+ // PR_FACT, PR_PREDECESSOR para chequear que la maquinaria
23
+ // compila funciones de aritmética básica. Ackermann queda fuera
24
+ // (es μ-recursiva, no PR), incluida como tope de potencia.
25
+ //
26
+ // 4. Witness de Rice: cualquier propiedad no trivial sobre el
27
+ // lenguaje aceptado por una TM es indecidible. Aquí no hay
28
+ // decisión real (ningún algoritmo puede tener éxito); damos un
29
+ // explicador que sólo verifica el predicado "es no trivial" sobre
30
+ // una muestra y devuelve la justificación clásica.
31
+ //
32
+ // Convenciones:
33
+ // • Cinta = array de símbolos; expansión perezosa con `blank`
34
+ // hacia ambos lados (se inserta blank cuando la cabeza pasa el
35
+ // borde). Para no mutar configuraciones previas devolvemos una
36
+ // copia (`step` y `trace` no comparten estructura).
37
+ // • Strings de entrada/salida son la concatenación de símbolos.
38
+ // Para `tmReverseString`, `tmCopy`, etc. el resultado se lee de
39
+ // la cinta en el rango no-blank al final.
40
+ // • PRF: usamos `number` con guardas (negativos → error; NaN →
41
+ // error). No intentamos manejar BigInt aquí — los tests caben en
42
+ // `number` cómodamente.
43
+ // ============================================================
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.PR_FACT = exports.PR_PREDECESSOR = exports.PR_POW = exports.PR_MUL = exports.PR_ADD = void 0;
46
+ exports.initialConfig = initialConfig;
47
+ exports.step = step;
48
+ exports.run = run;
49
+ exports.trace = trace;
50
+ exports.readTape = readTape;
51
+ exports.boundedHalts = boundedHalts;
52
+ exports.tmBinaryIncrement = tmBinaryIncrement;
53
+ exports.tmUnaryParity = tmUnaryParity;
54
+ exports.tmReverseString = tmReverseString;
55
+ exports.tmCopy = tmCopy;
56
+ exports.tmAddBinary = tmAddBinary;
57
+ exports.evalPR = evalPR;
58
+ exports.ackermann = ackermann;
59
+ exports.isInPR = isInPR;
60
+ exports.riceWitness = riceWitness;
61
+ /**
62
+ * Inicializa una configuración a partir de la entrada. La cinta arranca
63
+ * con los símbolos de `input`, cabeza en 0. Si la entrada es vacía la
64
+ * cinta arranca con un blank.
65
+ */
66
+ function initialConfig(M, input) {
67
+ const tape = input.length === 0 ? [M.blank] : Array.from(input);
68
+ return { state: M.initialState, tape, head: 0, step: 0 };
69
+ }
70
+ function findTransition(M, state, symbol) {
71
+ return M.transitions.find((t) => t.fromState === state && t.readSymbol === symbol);
72
+ }
73
+ /**
74
+ * Un paso de la TM. Devuelve la próxima configuración o un terminal.
75
+ * • Si el estado actual ya es de aceptación → 'halted-accept'.
76
+ * • Si es de rechazo → 'halted-reject'.
77
+ * • Si no hay transición desde (state, leído) → 'no-transition'.
78
+ */
79
+ function step(M, config) {
80
+ if (M.acceptStates.has(config.state))
81
+ return 'halted-accept';
82
+ if (M.rejectStates?.has(config.state))
83
+ return 'halted-reject';
84
+ // Expansión perezosa de la cinta a la izquierda
85
+ let tape = config.tape;
86
+ let head = config.head;
87
+ if (head < 0) {
88
+ const pad = new Array(-head).fill(M.blank);
89
+ tape = pad.concat(tape);
90
+ head = 0;
91
+ }
92
+ if (head >= tape.length) {
93
+ const extra = head - tape.length + 1;
94
+ tape = tape.concat(new Array(extra).fill(M.blank));
95
+ }
96
+ const read = tape[head] ?? M.blank;
97
+ const tr = findTransition(M, config.state, read);
98
+ if (!tr)
99
+ return 'no-transition';
100
+ const newTape = tape.slice();
101
+ newTape[head] = tr.writeSymbol;
102
+ let newHead = head;
103
+ if (tr.direction === 'L')
104
+ newHead -= 1;
105
+ else if (tr.direction === 'R')
106
+ newHead += 1;
107
+ // direction 'S' = stay
108
+ return {
109
+ state: tr.toState,
110
+ tape: newTape,
111
+ head: newHead,
112
+ step: config.step + 1,
113
+ };
114
+ }
115
+ /**
116
+ * Corre la TM hasta aceptar, rechazar, agotarse o quedar sin transición.
117
+ * `maxSteps` defaultea a 10_000.
118
+ */
119
+ function run(M, input, maxSteps = 10_000) {
120
+ let cfg = initialConfig(M, input);
121
+ for (let i = 0; i < maxSteps; i += 1) {
122
+ const next = step(M, cfg);
123
+ if (next === 'halted-accept')
124
+ return { result: 'accept', steps: cfg.step, finalConfig: cfg };
125
+ if (next === 'halted-reject')
126
+ return { result: 'reject', steps: cfg.step, finalConfig: cfg };
127
+ if (next === 'no-transition')
128
+ return { result: 'no-transition', steps: cfg.step, finalConfig: cfg };
129
+ cfg = next;
130
+ }
131
+ return { result: 'timeout', steps: cfg.step, finalConfig: cfg };
132
+ }
133
+ /**
134
+ * Lista todas las configuraciones generadas, hasta `maxSteps`.
135
+ * Incluye la configuración inicial. No incluye un sentinel para terminal.
136
+ */
137
+ function trace(M, input, maxSteps) {
138
+ const out = [];
139
+ let cfg = initialConfig(M, input);
140
+ out.push(cfg);
141
+ for (let i = 0; i < maxSteps; i += 1) {
142
+ const next = step(M, cfg);
143
+ if (typeof next === 'string')
144
+ return out;
145
+ out.push(next);
146
+ cfg = next;
147
+ }
148
+ return out;
149
+ }
150
+ /**
151
+ * Lectura útil de la cinta: la subcadena no-blank más larga centrada en
152
+ * la región explorada. Sirve para validar máquinas que escriben output
153
+ * en la cinta (binary increment, reverse, copy, etc.).
154
+ */
155
+ function readTape(M, config) {
156
+ let start = 0;
157
+ let end = config.tape.length;
158
+ while (start < end && config.tape[start] === M.blank)
159
+ start += 1;
160
+ while (end > start && config.tape[end - 1] === M.blank)
161
+ end -= 1;
162
+ return config.tape.slice(start, end).join('');
163
+ }
164
+ /**
165
+ * Halting acotado: ¿la TM para en ≤ `maxSteps` pasos?
166
+ * • `true` si para por aceptación, rechazo o falta de transición.
167
+ * • `false` técnicamente nunca se devuelve aquí — para devolver
168
+ * `false` con certeza haría falta resolver el halting problem, que
169
+ * es indecidible. Cuando agotamos el budget devolvemos `'unknown'`.
170
+ * Esta función es semi-decidible: reconoce las máquinas que paran,
171
+ * pero no decide el lenguaje complemento (las que no paran).
172
+ */
173
+ function boundedHalts(M, input, maxSteps) {
174
+ const r = run(M, input, maxSteps);
175
+ if (r.result === 'timeout')
176
+ return 'unknown';
177
+ return true;
178
+ }
179
+ // ── Máquinas estándar ───────────────────────────────────────
180
+ /**
181
+ * Incrementa un número binario (MSB first) en la cinta.
182
+ * Algoritmo: ir al final, retroceder convirtiendo 1→0 mientras haya
183
+ * acarreo; al primer 0 escribir 1 y aceptar. Si todo era 1, escribir
184
+ * 1 al borde izquierdo y aceptar.
185
+ */
186
+ function tmBinaryIncrement() {
187
+ return {
188
+ states: new Set(['q0', 'q1', 'q2', 'qa']),
189
+ alphabet: new Set(['0', '1']),
190
+ tapeAlphabet: new Set(['0', '1', 'B']),
191
+ blank: 'B',
192
+ initialState: 'q0',
193
+ acceptStates: new Set(['qa']),
194
+ transitions: [
195
+ // q0: ir a la derecha hasta encontrar blank
196
+ { fromState: 'q0', readSymbol: '0', toState: 'q0', writeSymbol: '0', direction: 'R' },
197
+ { fromState: 'q0', readSymbol: '1', toState: 'q0', writeSymbol: '1', direction: 'R' },
198
+ { fromState: 'q0', readSymbol: 'B', toState: 'q1', writeSymbol: 'B', direction: 'L' },
199
+ // q1: propagar acarreo
200
+ { fromState: 'q1', readSymbol: '0', toState: 'q2', writeSymbol: '1', direction: 'L' },
201
+ { fromState: 'q1', readSymbol: '1', toState: 'q1', writeSymbol: '0', direction: 'L' },
202
+ { fromState: 'q1', readSymbol: 'B', toState: 'qa', writeSymbol: '1', direction: 'S' },
203
+ // q2: terminar moviéndose al final
204
+ { fromState: 'q2', readSymbol: '0', toState: 'q2', writeSymbol: '0', direction: 'L' },
205
+ { fromState: 'q2', readSymbol: '1', toState: 'q2', writeSymbol: '1', direction: 'L' },
206
+ { fromState: 'q2', readSymbol: 'B', toState: 'qa', writeSymbol: 'B', direction: 'R' },
207
+ ],
208
+ };
209
+ }
210
+ /**
211
+ * Acepta sii la cantidad de 1s en la entrada (sobre alfabeto {1}) es par.
212
+ * Estados q0 = par hasta ahora, q1 = impar.
213
+ */
214
+ function tmUnaryParity() {
215
+ return {
216
+ states: new Set(['q0', 'q1', 'qa', 'qr']),
217
+ alphabet: new Set(['1']),
218
+ tapeAlphabet: new Set(['1', 'B']),
219
+ blank: 'B',
220
+ initialState: 'q0',
221
+ acceptStates: new Set(['qa']),
222
+ rejectStates: new Set(['qr']),
223
+ transitions: [
224
+ { fromState: 'q0', readSymbol: '1', toState: 'q1', writeSymbol: '1', direction: 'R' },
225
+ { fromState: 'q0', readSymbol: 'B', toState: 'qa', writeSymbol: 'B', direction: 'S' },
226
+ { fromState: 'q1', readSymbol: '1', toState: 'q0', writeSymbol: '1', direction: 'R' },
227
+ { fromState: 'q1', readSymbol: 'B', toState: 'qr', writeSymbol: 'B', direction: 'S' },
228
+ ],
229
+ };
230
+ }
231
+ /**
232
+ * Revierte una cadena sobre {a, b}. Algoritmo:
233
+ * 1. Marcar inicio (Sa, Sb) con un símbolo distintivo.
234
+ * 2. Encontrar el final y desplazar el símbolo del frente al fondo.
235
+ * 3. Repetir hasta agotar.
236
+ * Output: la cinta termina con el reverso de la entrada original.
237
+ *
238
+ * Implementación con cinta auxiliar a la derecha (más simple):
239
+ * Caminar a la derecha mientras se copian símbolos en orden inverso
240
+ * tras un separador. Al terminar borrar la entrada original.
241
+ *
242
+ * Para evitar complicaciones, esta versión usa una técnica de
243
+ * "shift left after marking": tras leer un símbolo, lo borra y lo
244
+ * reescribe al final del bloque restante.
245
+ *
246
+ * Nota: este algoritmo es O(n²) en pasos pero correcto.
247
+ */
248
+ function tmReverseString() {
249
+ // Estrategia:
250
+ // 1. init: pasamos a la derecha y escribimos un marcador '|' justo
251
+ // tras el último símbolo del input.
252
+ // 2. pickRight: vamos a la izquierda desde '|' hasta el primer
253
+ // símbolo del input por la derecha (el ÚLTIMO símbolo de la
254
+ // entrada original). Lo borramos y lo "cargamos" en el estado.
255
+ // Si en lugar de un símbolo encontramos el marcador izquierdo
256
+ // '^' → done. Si encontramos sólo blanks entre símbolos, los
257
+ // saltamos.
258
+ // 3. carry_X: caminamos a la derecha, pasando '|' y los símbolos
259
+ // ya escritos a la derecha del marcador, hasta encontrar el
260
+ // primer blank tras el output. Allí escribimos X. Esto pone el
261
+ // símbolo cargado al final del bloque de output → orden inverso.
262
+ // 4. rewind: volvemos al marcador '|' (atravesando los símbolos
263
+ // output) y desde ahí relanzamos pickRight.
264
+ // 5. Cuando pickRight ve '^' contiguo a '|' (input agotado) →
265
+ // borramos '^' y '|' y aceptamos.
266
+ //
267
+ // El marcador '^' se inserta al inicio extendiendo la cinta una
268
+ // posición a la izquierda. Como la TM no puede insertar fácilmente,
269
+ // arrancamos en init1 que escribe '^' en la posición 0 y desplaza
270
+ // todo a la derecha. Para evitar la sub-rutina de shift, optamos
271
+ // por una codificación más simple: el marcador izquierdo se pone
272
+ // a la primera posición *blank* a la izquierda. Como la cinta es
273
+ // ilimitada por la izquierda con blanks padded, podemos ir un paso
274
+ // L del primer símbolo y escribir '^' allí (eso reserva 1 blank a
275
+ // la izquierda del input).
276
+ const symbols = ['a', 'b', 'c'];
277
+ const transitions = [];
278
+ // start: ir UNA posición a la izquierda y escribir '^', luego volver a la derecha.
279
+ transitions.push({
280
+ fromState: 'start',
281
+ readSymbol: 'a',
282
+ toState: 'mark',
283
+ writeSymbol: 'a',
284
+ direction: 'L',
285
+ });
286
+ transitions.push({
287
+ fromState: 'start',
288
+ readSymbol: 'b',
289
+ toState: 'mark',
290
+ writeSymbol: 'b',
291
+ direction: 'L',
292
+ });
293
+ transitions.push({
294
+ fromState: 'start',
295
+ readSymbol: 'c',
296
+ toState: 'mark',
297
+ writeSymbol: 'c',
298
+ direction: 'L',
299
+ });
300
+ transitions.push({
301
+ fromState: 'start',
302
+ readSymbol: 'B',
303
+ toState: 'mark',
304
+ writeSymbol: 'B',
305
+ direction: 'L',
306
+ });
307
+ transitions.push({
308
+ fromState: 'mark',
309
+ readSymbol: 'B',
310
+ toState: 'init',
311
+ writeSymbol: '^',
312
+ direction: 'R',
313
+ });
314
+ // init: pasar a la derecha y poner '|' al final del input
315
+ for (const s of symbols) {
316
+ transitions.push({
317
+ fromState: 'init',
318
+ readSymbol: s,
319
+ toState: 'init',
320
+ writeSymbol: s,
321
+ direction: 'R',
322
+ });
323
+ }
324
+ transitions.push({
325
+ fromState: 'init',
326
+ readSymbol: 'B',
327
+ toState: 'pickRight',
328
+ writeSymbol: '|',
329
+ direction: 'L',
330
+ });
331
+ // pickRight: ir a la izquierda desde '|' buscando el último símbolo.
332
+ for (const s of symbols) {
333
+ transitions.push({
334
+ fromState: 'pickRight',
335
+ readSymbol: s,
336
+ toState: `carry_${s}`,
337
+ writeSymbol: 'B',
338
+ direction: 'R',
339
+ });
340
+ }
341
+ transitions.push({
342
+ fromState: 'pickRight',
343
+ readSymbol: 'B',
344
+ toState: 'pickRight',
345
+ writeSymbol: 'B',
346
+ direction: 'L',
347
+ });
348
+ // si pickRight ve '^' (input agotado) → done
349
+ transitions.push({
350
+ fromState: 'pickRight',
351
+ readSymbol: '^',
352
+ toState: 'done',
353
+ writeSymbol: 'B',
354
+ direction: 'R',
355
+ });
356
+ // carry_X: caminar a la derecha cruzando blanks ya borrados, '|', y
357
+ // los símbolos output existentes, hasta el primer blank tras output.
358
+ for (const s of symbols) {
359
+ const carry = `carry_${s}`;
360
+ transitions.push({
361
+ fromState: carry,
362
+ readSymbol: 'B',
363
+ toState: carry,
364
+ writeSymbol: 'B',
365
+ direction: 'R',
366
+ });
367
+ transitions.push({
368
+ fromState: carry,
369
+ readSymbol: '|',
370
+ toState: `carry_${s}_post`,
371
+ writeSymbol: '|',
372
+ direction: 'R',
373
+ });
374
+ }
375
+ for (const s of symbols) {
376
+ const post = `carry_${s}_post`;
377
+ for (const t of symbols) {
378
+ transitions.push({
379
+ fromState: post,
380
+ readSymbol: t,
381
+ toState: post,
382
+ writeSymbol: t,
383
+ direction: 'R',
384
+ });
385
+ }
386
+ transitions.push({
387
+ fromState: post,
388
+ readSymbol: 'B',
389
+ toState: 'rewind',
390
+ writeSymbol: s,
391
+ direction: 'L',
392
+ });
393
+ }
394
+ // rewind: volver hasta '|' atravesando los símbolos output.
395
+ for (const s of symbols) {
396
+ transitions.push({
397
+ fromState: 'rewind',
398
+ readSymbol: s,
399
+ toState: 'rewind',
400
+ writeSymbol: s,
401
+ direction: 'L',
402
+ });
403
+ }
404
+ transitions.push({
405
+ fromState: 'rewind',
406
+ readSymbol: '|',
407
+ toState: 'pickRight',
408
+ writeSymbol: '|',
409
+ direction: 'L',
410
+ });
411
+ // done: borrar '|' y aceptar (cuando pickRight vio '^' la cabeza fue R 1).
412
+ for (const s of symbols) {
413
+ transitions.push({
414
+ fromState: 'done',
415
+ readSymbol: s,
416
+ toState: 'done',
417
+ writeSymbol: s,
418
+ direction: 'R',
419
+ });
420
+ }
421
+ transitions.push({
422
+ fromState: 'done',
423
+ readSymbol: 'B',
424
+ toState: 'done',
425
+ writeSymbol: 'B',
426
+ direction: 'R',
427
+ });
428
+ transitions.push({
429
+ fromState: 'done',
430
+ readSymbol: '|',
431
+ toState: 'qa',
432
+ writeSymbol: 'B',
433
+ direction: 'S',
434
+ });
435
+ const stateSet = new Set(['start', 'mark', 'init', 'pickRight', 'rewind', 'done', 'qa']);
436
+ for (const s of symbols) {
437
+ stateSet.add(`carry_${s}`);
438
+ stateSet.add(`carry_${s}_post`);
439
+ }
440
+ return {
441
+ states: stateSet,
442
+ alphabet: new Set(symbols),
443
+ tapeAlphabet: new Set([...symbols, '|', '^', 'B']),
444
+ blank: 'B',
445
+ initialState: 'start',
446
+ acceptStates: new Set(['qa']),
447
+ transitions,
448
+ };
449
+ }
450
+ /**
451
+ * Copia w → w#w sobre {a, b}. El '#' se inserta automáticamente y la
452
+ * copia queda a la derecha. Algoritmo análogo a reverse pero copiando
453
+ * en orden directo (marcamos cada símbolo procesado con mayúscula).
454
+ */
455
+ function tmCopy() {
456
+ return {
457
+ states: new Set([
458
+ 'scan',
459
+ 'next',
460
+ 'copyA',
461
+ 'copyB',
462
+ 'placeA',
463
+ 'placeB',
464
+ 'back',
465
+ 'restore',
466
+ 'done',
467
+ 'qa',
468
+ ]),
469
+ alphabet: new Set(['a', 'b']),
470
+ tapeAlphabet: new Set(['a', 'b', 'A', 'B0', '#', 'B']),
471
+ blank: 'B',
472
+ initialState: 'scan',
473
+ acceptStates: new Set(['qa']),
474
+ transitions: [
475
+ // scan: ir al final y poner '#'
476
+ { fromState: 'scan', readSymbol: 'a', toState: 'scan', writeSymbol: 'a', direction: 'R' },
477
+ { fromState: 'scan', readSymbol: 'b', toState: 'scan', writeSymbol: 'b', direction: 'R' },
478
+ { fromState: 'scan', readSymbol: 'B', toState: 'back', writeSymbol: '#', direction: 'L' },
479
+ // back: volver al inicio (pasando por #, output, marcas y blanks dentro del segmento)
480
+ { fromState: 'back', readSymbol: 'a', toState: 'back', writeSymbol: 'a', direction: 'L' },
481
+ { fromState: 'back', readSymbol: 'b', toState: 'back', writeSymbol: 'b', direction: 'L' },
482
+ { fromState: 'back', readSymbol: 'A', toState: 'back', writeSymbol: 'A', direction: 'L' },
483
+ { fromState: 'back', readSymbol: 'B0', toState: 'back', writeSymbol: 'B0', direction: 'L' },
484
+ { fromState: 'back', readSymbol: '#', toState: 'back', writeSymbol: '#', direction: 'L' },
485
+ { fromState: 'back', readSymbol: 'B', toState: 'next', writeSymbol: 'B', direction: 'R' },
486
+ // next: si encuentras a/b, marcarlo y empezar copy
487
+ { fromState: 'next', readSymbol: 'a', toState: 'copyA', writeSymbol: 'A', direction: 'R' },
488
+ { fromState: 'next', readSymbol: 'b', toState: 'copyB', writeSymbol: 'B0', direction: 'R' },
489
+ { fromState: 'next', readSymbol: 'A', toState: 'next', writeSymbol: 'A', direction: 'R' },
490
+ { fromState: 'next', readSymbol: 'B0', toState: 'next', writeSymbol: 'B0', direction: 'R' },
491
+ { fromState: 'next', readSymbol: '#', toState: 'restore', writeSymbol: '#', direction: 'L' },
492
+ // copyA: ir a la derecha hasta pasar '#' y escribir 'a' donde haya blank
493
+ { fromState: 'copyA', readSymbol: 'a', toState: 'copyA', writeSymbol: 'a', direction: 'R' },
494
+ { fromState: 'copyA', readSymbol: 'b', toState: 'copyA', writeSymbol: 'b', direction: 'R' },
495
+ { fromState: 'copyA', readSymbol: '#', toState: 'placeA', writeSymbol: '#', direction: 'R' },
496
+ { fromState: 'placeA', readSymbol: 'a', toState: 'placeA', writeSymbol: 'a', direction: 'R' },
497
+ { fromState: 'placeA', readSymbol: 'b', toState: 'placeA', writeSymbol: 'b', direction: 'R' },
498
+ { fromState: 'placeA', readSymbol: 'B', toState: 'back', writeSymbol: 'a', direction: 'L' },
499
+ // copyB
500
+ { fromState: 'copyB', readSymbol: 'a', toState: 'copyB', writeSymbol: 'a', direction: 'R' },
501
+ { fromState: 'copyB', readSymbol: 'b', toState: 'copyB', writeSymbol: 'b', direction: 'R' },
502
+ { fromState: 'copyB', readSymbol: '#', toState: 'placeB', writeSymbol: '#', direction: 'R' },
503
+ { fromState: 'placeB', readSymbol: 'a', toState: 'placeB', writeSymbol: 'a', direction: 'R' },
504
+ { fromState: 'placeB', readSymbol: 'b', toState: 'placeB', writeSymbol: 'b', direction: 'R' },
505
+ { fromState: 'placeB', readSymbol: 'B', toState: 'back', writeSymbol: 'b', direction: 'L' },
506
+ // restore: ir a la izquierda y devolver A→a, B0→b
507
+ {
508
+ fromState: 'restore',
509
+ readSymbol: 'A',
510
+ toState: 'restore',
511
+ writeSymbol: 'a',
512
+ direction: 'L',
513
+ },
514
+ {
515
+ fromState: 'restore',
516
+ readSymbol: 'B0',
517
+ toState: 'restore',
518
+ writeSymbol: 'b',
519
+ direction: 'L',
520
+ },
521
+ {
522
+ fromState: 'restore',
523
+ readSymbol: 'a',
524
+ toState: 'restore',
525
+ writeSymbol: 'a',
526
+ direction: 'L',
527
+ },
528
+ {
529
+ fromState: 'restore',
530
+ readSymbol: 'b',
531
+ toState: 'restore',
532
+ writeSymbol: 'b',
533
+ direction: 'L',
534
+ },
535
+ { fromState: 'restore', readSymbol: 'B', toState: 'qa', writeSymbol: 'B', direction: 'R' },
536
+ ],
537
+ };
538
+ }
539
+ // Patch: la transición `back → next` necesita un estado adicional `next`.
540
+ // Agregamos `'next'` al set de estados arriba.
541
+ /**
542
+ * Suma con `a` en binario y `b` en unario, formato "<a>+<b>" donde
543
+ * a ∈ {0,1}* (MSB-first), b ∈ {1}*.
544
+ *
545
+ * Mantener `b` unario evita la coreografía de decremento binario (que
546
+ * agrega ~10 estados sin enseñar nada nuevo) y muestra claramente la
547
+ * técnica de "incrementar `a` una vez por cada token de `b`".
548
+ *
549
+ * Algoritmo:
550
+ * 1. Ir al final.
551
+ * 2. Si la última posición es '1' (un token de b), borrarlo y entrar
552
+ * en `incA`: incrementar `a` y luego volver al final.
553
+ * 3. Si la última posición es '+' (b vacío), borrarlo: la cinta queda
554
+ * con sólo `a` (el resultado).
555
+ */
556
+ function tmAddBinary() {
557
+ return {
558
+ states: new Set(['s0', 'check', 'incA', 'carryLeft', 'returnEnd', 'qa']),
559
+ alphabet: new Set(['0', '1', '+']),
560
+ tapeAlphabet: new Set(['0', '1', '+', 'B']),
561
+ blank: 'B',
562
+ initialState: 's0',
563
+ acceptStates: new Set(['qa']),
564
+ transitions: [
565
+ // s0: ir a la derecha hasta blank
566
+ { fromState: 's0', readSymbol: '0', toState: 's0', writeSymbol: '0', direction: 'R' },
567
+ { fromState: 's0', readSymbol: '1', toState: 's0', writeSymbol: '1', direction: 'R' },
568
+ { fromState: 's0', readSymbol: '+', toState: 's0', writeSymbol: '+', direction: 'R' },
569
+ { fromState: 's0', readSymbol: 'B', toState: 'check', writeSymbol: 'B', direction: 'L' },
570
+ // check: ¿es '1' (un token b) o '+' (terminamos)?
571
+ { fromState: 'check', readSymbol: '1', toState: 'incA', writeSymbol: 'B', direction: 'L' },
572
+ { fromState: 'check', readSymbol: '+', toState: 'qa', writeSymbol: 'B', direction: 'S' },
573
+ // incA: caminar a la izquierda saltando '1's de b hasta '+', luego al LSB de a.
574
+ { fromState: 'incA', readSymbol: '1', toState: 'incA', writeSymbol: '1', direction: 'L' },
575
+ {
576
+ fromState: 'incA',
577
+ readSymbol: '+',
578
+ toState: 'carryLeft',
579
+ writeSymbol: '+',
580
+ direction: 'L',
581
+ },
582
+ // carryLeft: propagar acarreo binario de derecha a izquierda dentro de a.
583
+ {
584
+ fromState: 'carryLeft',
585
+ readSymbol: '0',
586
+ toState: 'returnEnd',
587
+ writeSymbol: '1',
588
+ direction: 'R',
589
+ },
590
+ {
591
+ fromState: 'carryLeft',
592
+ readSymbol: '1',
593
+ toState: 'carryLeft',
594
+ writeSymbol: '0',
595
+ direction: 'L',
596
+ },
597
+ {
598
+ fromState: 'carryLeft',
599
+ readSymbol: 'B',
600
+ toState: 'returnEnd',
601
+ writeSymbol: '1',
602
+ direction: 'R',
603
+ },
604
+ // returnEnd: ir al final (al blank derecho) y volver a check.
605
+ {
606
+ fromState: 'returnEnd',
607
+ readSymbol: '0',
608
+ toState: 'returnEnd',
609
+ writeSymbol: '0',
610
+ direction: 'R',
611
+ },
612
+ {
613
+ fromState: 'returnEnd',
614
+ readSymbol: '1',
615
+ toState: 'returnEnd',
616
+ writeSymbol: '1',
617
+ direction: 'R',
618
+ },
619
+ {
620
+ fromState: 'returnEnd',
621
+ readSymbol: '+',
622
+ toState: 'returnEnd',
623
+ writeSymbol: '+',
624
+ direction: 'R',
625
+ },
626
+ {
627
+ fromState: 'returnEnd',
628
+ readSymbol: 'B',
629
+ toState: 'check',
630
+ writeSymbol: 'B',
631
+ direction: 'L',
632
+ },
633
+ ],
634
+ };
635
+ }
636
+ /**
637
+ * Semántica de PRF:
638
+ * • zero() = 0
639
+ * • succ(x) = x + 1
640
+ * • U^n_i(x1..xn) = x_i
641
+ * • comp(h, g1..gk)(x1..xn) = h(g1(x1..xn), ..., gk(x1..xn))
642
+ * • rec(base, step):
643
+ * f(0, x1..xn) = base(x1..xn)
644
+ * f(y+1, x1..xn) = step(y, f(y, x1..xn), x1..xn)
645
+ *
646
+ * El argumento "iterado" es el primero (convención común). `args[0]` es
647
+ * el contador en `rec`.
648
+ */
649
+ function evalPR(f, args) {
650
+ for (const a of args) {
651
+ if (!Number.isFinite(a) || a < 0 || !Number.isInteger(a)) {
652
+ throw new Error(`evalPR: argumento inválido ${String(a)}`);
653
+ }
654
+ }
655
+ switch (f.kind) {
656
+ case 'zero':
657
+ return 0;
658
+ case 'succ': {
659
+ const x = args[0];
660
+ if (x === undefined)
661
+ throw new Error('succ: falta argumento');
662
+ return x + 1;
663
+ }
664
+ case 'proj': {
665
+ if (f.i < 1 || f.i > f.n)
666
+ throw new Error('proj: índice fuera de rango');
667
+ if (args.length < f.n)
668
+ throw new Error('proj: faltan argumentos');
669
+ const v = args[f.i - 1];
670
+ if (v === undefined)
671
+ throw new Error('proj: undefined');
672
+ return v;
673
+ }
674
+ case 'comp': {
675
+ const innerVals = f.inner.map((g) => evalPR(g, args));
676
+ return evalPR(f.outer, innerVals);
677
+ }
678
+ case 'rec': {
679
+ const y = args[0];
680
+ if (y === undefined)
681
+ throw new Error('rec: falta contador');
682
+ const rest = args.slice(1);
683
+ let acc = evalPR(f.base, rest);
684
+ for (let k = 0; k < y; k += 1) {
685
+ acc = evalPR(f.step, [k, acc, ...rest]);
686
+ }
687
+ return acc;
688
+ }
689
+ }
690
+ }
691
+ // Helpers para construir PRFn más legibles.
692
+ const zero = { kind: 'zero' };
693
+ const succ = { kind: 'succ' };
694
+ const proj = (n, i) => ({ kind: 'proj', n, i });
695
+ const comp = (outer, ...inner) => ({ kind: 'comp', outer, inner });
696
+ const rec = (base, step) => ({ kind: 'rec', base, step });
697
+ /**
698
+ * Suma: add(0, y) = y, add(x+1, y) = succ(add(x, y))
699
+ * base = U^1_1 (identidad en y)
700
+ * step = succ ∘ U^3_2 (toma f(x,y) y le aplica succ)
701
+ *
702
+ * En nuestra convención args[0] es el contador → add(x, y).
703
+ */
704
+ exports.PR_ADD = rec(proj(1, 1), comp(succ, proj(3, 2)));
705
+ /**
706
+ * Multiplicación: mul(0, y) = 0, mul(x+1, y) = add(mul(x,y), y)
707
+ * base = zero (después de proyectar y fuera)
708
+ * step = add(f(x,y), y)
709
+ *
710
+ * base: el caso 0 → 0. Es la función constante 0 sobre 1 argumento:
711
+ * const0(y) = zero ∘ U^1_1, pero zero ignora sus argumentos.
712
+ * En este eval, zero retorna 0 sin importar args.
713
+ */
714
+ exports.PR_MUL = rec(comp(zero, proj(1, 1)), comp(exports.PR_ADD, proj(3, 2), proj(3, 3)));
715
+ /**
716
+ * Potencia: pow(x, y) = y^x (iterando sobre primer argumento).
717
+ * pow(0, y) = 1
718
+ * pow(x+1, y) = mul(pow(x,y), y)
719
+ */
720
+ const ONE_FN = comp(succ, comp(zero, proj(1, 1))); // succ(0) = 1
721
+ exports.PR_POW = rec(ONE_FN, comp(exports.PR_MUL, proj(3, 2), proj(3, 3)));
722
+ /**
723
+ * Predecesor: pred(0) = 0, pred(x+1) = x.
724
+ * rec con base = zero, step = U^2_1 (devuelve y, el contador previo).
725
+ */
726
+ exports.PR_PREDECESSOR = rec(zero, proj(2, 1));
727
+ /**
728
+ * Factorial: fact(0) = 1, fact(x+1) = mul(succ(x), fact(x)).
729
+ *
730
+ * En recursión: contador y, acumulador f(y), sin args extra. Step recibe
731
+ * (y, f(y)) y debe devolver mul(succ(y), f(y)).
732
+ *
733
+ * Cuidado: aquí args[0]=y es el "k" del bucle (0-indexed), por lo que
734
+ * succ(y) = y+1 = el siguiente número a multiplicar.
735
+ */
736
+ exports.PR_FACT = rec(comp(succ, zero), // base = 1
737
+ comp(exports.PR_MUL, comp(succ, proj(2, 1)), proj(2, 2)));
738
+ // ── Ackermann (no PR) ───────────────────────────────────────
739
+ /**
740
+ * Función de Ackermann (Peter):
741
+ * A(0, n) = n + 1
742
+ * A(m+1, 0) = A(m, 1)
743
+ * A(m+1, n+1) = A(m, A(m+1, n))
744
+ *
745
+ * Crece más rápido que toda PRF: A(m, n) es la prueba canónica de que
746
+ * existen funciones recursivas totales no primitivas recursivas.
747
+ *
748
+ * Implementación iterativa por stack para esquivar el call-stack JS.
749
+ */
750
+ function ackermann(m, n) {
751
+ if (!Number.isInteger(m) || !Number.isInteger(n) || m < 0 || n < 0) {
752
+ throw new Error('ackermann: m,n deben ser enteros ≥ 0');
753
+ }
754
+ const stack = [m];
755
+ let curN = n;
756
+ while (stack.length > 0) {
757
+ const curM = stack.pop();
758
+ if (curM === 0) {
759
+ curN = curN + 1;
760
+ }
761
+ else if (curN === 0) {
762
+ stack.push(curM - 1);
763
+ curN = 1;
764
+ }
765
+ else {
766
+ stack.push(curM - 1);
767
+ stack.push(curM);
768
+ curN = curN - 1;
769
+ }
770
+ }
771
+ return curN;
772
+ }
773
+ /**
774
+ * Test heurístico de "esta función podría ser PR": evalúa la función
775
+ * sobre `samples` puntos pequeños y la compara con el patrón de
776
+ * crecimiento de Ackermann (que escapa a PR). Es estrictamente una
777
+ * heurística — no es un decisor.
778
+ *
779
+ * • Si la función supera a A(samples, samples) en algún punto pequeño
780
+ * → likely = false (probablemente no es PR).
781
+ * • Si nunca crece más rápido que cuadrático/exponencial moderado →
782
+ * likely = true.
783
+ */
784
+ function isInPR(f, samples = 4) {
785
+ let lastRatio = 1;
786
+ for (let n = 1; n <= samples; n += 1) {
787
+ const v = f(n);
788
+ if (!Number.isFinite(v) || v < 0)
789
+ return { likely: false };
790
+ const prevV = f(n - 1);
791
+ const ratio = prevV === 0 ? v : v / prevV;
792
+ // Comparar con un "horizonte de Ackermann": si f(n) > A(2, n+3), lo
793
+ // tomamos como señal de crecimiento súper-PR moderado. Esto es
794
+ // intencionadamente generoso porque casi todo lo "normal" cae aquí.
795
+ const ack = ackermann(2, Math.min(n + 3, 8));
796
+ if (v > ack * 1_000_000)
797
+ return { likely: false, estimate: ratio };
798
+ lastRatio = ratio;
799
+ }
800
+ return { likely: true, estimate: lastRatio };
801
+ }
802
+ // ── Witness de Rice ─────────────────────────────────────────
803
+ /**
804
+ * Rice (1953): toda propiedad **no trivial** sobre el lenguaje aceptado
805
+ * por una TM (es decir, sobre el comportamiento input/output observable)
806
+ * es **indecidible**.
807
+ *
808
+ * No podemos *decidir* la propiedad — eso es justo lo que el teorema
809
+ * niega. Lo que sí podemos es **verificar el predicado de Rice**: la
810
+ * propiedad debe ser
811
+ *
812
+ * 1. extensional (depende sólo del lenguaje, no del código),
813
+ * 2. no vacía (alguna TM la satisface),
814
+ * 3. no total (alguna TM no la satisface).
815
+ *
816
+ * Esta función toma el predicado, lo evalúa sobre un muestreo finito de
817
+ * TMs conocidas y, si encuentra una `M0` que la satisface y una `M1`
818
+ * que no, devuelve `undecidable = true` con explicación. Si todas las
819
+ * TMs de la muestra dan la misma respuesta no podemos concluir nada
820
+ * (la propiedad podría ser trivial, o la muestra puede ser muy chica).
821
+ */
822
+ function riceWitness(property, sampleSize = 5) {
823
+ const samples = [
824
+ tmBinaryIncrement(),
825
+ tmUnaryParity(),
826
+ tmReverseString(),
827
+ tmCopy(),
828
+ tmAddBinary(),
829
+ ].slice(0, Math.max(2, sampleSize));
830
+ let sawTrue = false;
831
+ let sawFalse = false;
832
+ for (const m of samples) {
833
+ if (property(m))
834
+ sawTrue = true;
835
+ else
836
+ sawFalse = true;
837
+ if (sawTrue && sawFalse) {
838
+ return {
839
+ undecidable: true,
840
+ explanation: 'La propiedad es no trivial (alguna TM la satisface y otra no). Por el teorema de Rice (1953), su decisión sobre todas las TMs es indecidible: no existe algoritmo que reciba una codificación de TM y responda sí/no para la propiedad.',
841
+ };
842
+ }
843
+ }
844
+ return {
845
+ undecidable: false,
846
+ explanation: sawTrue
847
+ ? 'La muestra es uniformemente positiva: la propiedad podría ser trivialmente verdadera (todas las TMs la satisfacen). Sin más evidencia no podemos invocar Rice.'
848
+ : 'La muestra es uniformemente negativa: la propiedad podría ser trivialmente falsa. Sin más evidencia no podemos invocar Rice.',
849
+ };
850
+ }
851
+ //# sourceMappingURL=index.js.map