@hviana/sema 0.1.5 → 0.1.6

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 (160) hide show
  1. package/AGENTS.md +6 -5
  2. package/CITATION.cff +49 -0
  3. package/HOW_IT_WORKS.md +11 -12
  4. package/README.md +7 -5
  5. package/dist/example/demo.js +25 -25
  6. package/dist/example/train_base.d.ts +19 -21
  7. package/dist/example/train_base.js +1687 -1952
  8. package/dist/src/alphabet.d.ts +3 -3
  9. package/dist/src/alphabet.js +24 -27
  10. package/dist/src/alu/src/alu.d.ts +169 -194
  11. package/dist/src/alu/src/alu.js +374 -414
  12. package/dist/src/alu/src/expr.d.ts +36 -43
  13. package/dist/src/alu/src/expr.js +252 -278
  14. package/dist/src/alu/src/index.d.ts +9 -98
  15. package/dist/src/alu/src/index.js +10 -64
  16. package/dist/src/alu/src/kernel-arith.d.ts +1 -5
  17. package/dist/src/alu/src/kernel-arith.js +195 -285
  18. package/dist/src/alu/src/kernel-bits.d.ts +1 -5
  19. package/dist/src/alu/src/kernel-bits.js +81 -115
  20. package/dist/src/alu/src/kernel-logic.js +33 -63
  21. package/dist/src/alu/src/kernel-nd.js +155 -195
  22. package/dist/src/alu/src/kernel-numeric.d.ts +16 -80
  23. package/dist/src/alu/src/kernel-numeric.js +259 -331
  24. package/dist/src/alu/src/operation.d.ts +112 -132
  25. package/dist/src/alu/src/operation.js +149 -163
  26. package/dist/src/alu/src/parser.d.ts +168 -175
  27. package/dist/src/alu/src/parser.js +382 -421
  28. package/dist/src/alu/src/resonance.d.ts +16 -25
  29. package/dist/src/alu/src/resonance.js +49 -56
  30. package/dist/src/alu/src/text.d.ts +3 -7
  31. package/dist/src/alu/src/text.js +31 -37
  32. package/dist/src/alu/src/value.d.ts +14 -14
  33. package/dist/src/alu/src/value.js +150 -160
  34. package/dist/src/alu/test/alu.test.js +543 -656
  35. package/dist/src/bytes.d.ts +1 -5
  36. package/dist/src/bytes.js +33 -40
  37. package/dist/src/config.d.ts +99 -102
  38. package/dist/src/config.js +78 -83
  39. package/dist/src/derive/src/deduction.d.ts +60 -62
  40. package/dist/src/derive/src/deduction.js +103 -109
  41. package/dist/src/derive/src/index.d.ts +1 -7
  42. package/dist/src/derive/src/priority-queue.d.ts +8 -8
  43. package/dist/src/derive/src/priority-queue.js +57 -61
  44. package/dist/src/derive/src/rewrite.d.ts +15 -18
  45. package/dist/src/derive/src/rewrite.js +59 -67
  46. package/dist/src/derive/src/trie.d.ts +56 -56
  47. package/dist/src/derive/src/trie.js +175 -179
  48. package/dist/src/derive/test/derive.test.js +96 -100
  49. package/dist/src/extension.d.ts +13 -16
  50. package/dist/src/geometry.d.ts +17 -42
  51. package/dist/src/geometry.js +235 -266
  52. package/dist/src/index.d.ts +2 -17
  53. package/dist/src/index.js +2 -12
  54. package/dist/src/ingest-cache.d.ts +25 -30
  55. package/dist/src/ingest-cache.js +108 -127
  56. package/dist/src/mind/articulation.d.ts +1 -5
  57. package/dist/src/mind/articulation.js +77 -112
  58. package/dist/src/mind/attention.d.ts +40 -108
  59. package/dist/src/mind/attention.js +749 -871
  60. package/dist/src/mind/canonical.d.ts +4 -19
  61. package/dist/src/mind/canonical.js +27 -31
  62. package/dist/src/mind/graph-search.d.ts +201 -225
  63. package/dist/src/mind/graph-search.js +742 -821
  64. package/dist/src/mind/index.d.ts +2 -10
  65. package/dist/src/mind/junction.d.ts +31 -58
  66. package/dist/src/mind/junction.js +172 -237
  67. package/dist/src/mind/learning.d.ts +16 -52
  68. package/dist/src/mind/learning.js +143 -165
  69. package/dist/src/mind/match.d.ts +20 -69
  70. package/dist/src/mind/match.js +259 -318
  71. package/dist/src/mind/mechanisms/alu.js +16 -16
  72. package/dist/src/mind/mechanisms/cast.d.ts +9 -13
  73. package/dist/src/mind/mechanisms/cast.js +363 -456
  74. package/dist/src/mind/mechanisms/confluence.d.ts +8 -12
  75. package/dist/src/mind/mechanisms/confluence.js +152 -183
  76. package/dist/src/mind/mechanisms/cover.d.ts +2 -8
  77. package/dist/src/mind/mechanisms/cover.js +148 -210
  78. package/dist/src/mind/mechanisms/extraction.d.ts +8 -34
  79. package/dist/src/mind/mechanisms/extraction.js +234 -288
  80. package/dist/src/mind/mechanisms/recall.d.ts +6 -10
  81. package/dist/src/mind/mechanisms/recall.js +126 -185
  82. package/dist/src/mind/mind.d.ts +129 -154
  83. package/dist/src/mind/mind.js +258 -288
  84. package/dist/src/mind/pipeline-mechanism.d.ts +112 -124
  85. package/dist/src/mind/pipeline-mechanism.js +161 -172
  86. package/dist/src/mind/pipeline.d.ts +4 -14
  87. package/dist/src/mind/pipeline.js +125 -189
  88. package/dist/src/mind/primitives.d.ts +8 -32
  89. package/dist/src/mind/primitives.js +99 -117
  90. package/dist/src/mind/rationale.d.ts +86 -98
  91. package/dist/src/mind/rationale.js +113 -121
  92. package/dist/src/mind/reasoning.d.ts +2 -13
  93. package/dist/src/mind/reasoning.js +129 -166
  94. package/dist/src/mind/recognition.d.ts +1 -4
  95. package/dist/src/mind/recognition.js +183 -208
  96. package/dist/src/mind/resonance.d.ts +5 -22
  97. package/dist/src/mind/resonance.js +0 -0
  98. package/dist/src/mind/trace.d.ts +6 -25
  99. package/dist/src/mind/trace.js +50 -58
  100. package/dist/src/mind/traverse.d.ts +16 -58
  101. package/dist/src/mind/traverse.js +304 -357
  102. package/dist/src/mind/types.d.ts +120 -127
  103. package/dist/src/mind/types.js +60 -69
  104. package/dist/src/rabitq-ivf/src/database.d.ts +113 -0
  105. package/dist/src/rabitq-ivf/src/database.js +201 -0
  106. package/dist/src/rabitq-ivf/src/index.d.ts +7 -0
  107. package/dist/src/{rabitq-hnsw → rabitq-ivf}/src/index.js +1 -3
  108. package/dist/src/rabitq-ivf/src/ivf.d.ts +200 -0
  109. package/dist/src/rabitq-ivf/src/ivf.js +1165 -0
  110. package/dist/src/rabitq-ivf/src/prng.d.ts +19 -0
  111. package/dist/src/rabitq-ivf/src/prng.js +36 -0
  112. package/dist/src/rabitq-ivf/src/rabitq.d.ts +95 -0
  113. package/dist/src/rabitq-ivf/src/rabitq.js +283 -0
  114. package/dist/src/sema.d.ts +9 -13
  115. package/dist/src/sema.js +26 -40
  116. package/dist/src/store-sqlite.d.ts +169 -166
  117. package/dist/src/store-sqlite.js +762 -662
  118. package/dist/src/store.d.ts +586 -630
  119. package/dist/src/store.js +1423 -1581
  120. package/dist/src/vec.d.ts +5 -9
  121. package/dist/src/vec.js +61 -73
  122. package/example/train_base.ts +13 -10
  123. package/package.json +1 -1
  124. package/src/alu/README.md +1 -1
  125. package/src/alu/src/index.ts +1 -1
  126. package/src/config.ts +19 -27
  127. package/src/index.ts +6 -11
  128. package/src/rabitq-ivf/README.md +56 -0
  129. package/src/rabitq-ivf/src/database.ts +276 -0
  130. package/src/{rabitq-hnsw → rabitq-ivf}/src/index.ts +2 -5
  131. package/src/rabitq-ivf/src/ivf.ts +1330 -0
  132. package/src/{rabitq-hnsw → rabitq-ivf}/src/prng.ts +1 -1
  133. package/src/store-sqlite.ts +196 -9
  134. package/src/store.ts +8 -32
  135. package/test/08-storage.test.mjs +3 -3
  136. package/test/14-scaling.test.mjs +2 -2
  137. package/test/35-ivf.test.mjs +263 -0
  138. package/test/36-bloom.test.mjs +123 -0
  139. package/dist/src/rabitq-hnsw/src/database.d.ts +0 -202
  140. package/dist/src/rabitq-hnsw/src/database.js +0 -405
  141. package/dist/src/rabitq-hnsw/src/heap.d.ts +0 -22
  142. package/dist/src/rabitq-hnsw/src/heap.js +0 -94
  143. package/dist/src/rabitq-hnsw/src/hnsw.d.ts +0 -125
  144. package/dist/src/rabitq-hnsw/src/hnsw.js +0 -500
  145. package/dist/src/rabitq-hnsw/src/index.d.ts +0 -15
  146. package/dist/src/rabitq-hnsw/src/prng.d.ts +0 -19
  147. package/dist/src/rabitq-hnsw/src/prng.js +0 -38
  148. package/dist/src/rabitq-hnsw/src/rabitq.d.ts +0 -95
  149. package/dist/src/rabitq-hnsw/src/rabitq.js +0 -299
  150. package/dist/src/rabitq-hnsw/src/store.d.ts +0 -162
  151. package/dist/src/rabitq-hnsw/src/store.js +0 -916
  152. package/dist/src/rabitq-hnsw/test/hnsw.test.d.ts +0 -1
  153. package/dist/src/rabitq-hnsw/test/hnsw.test.js +0 -1197
  154. package/src/rabitq-hnsw/README.md +0 -303
  155. package/src/rabitq-hnsw/src/database.ts +0 -492
  156. package/src/rabitq-hnsw/src/heap.ts +0 -90
  157. package/src/rabitq-hnsw/src/hnsw.ts +0 -514
  158. package/src/rabitq-hnsw/src/store.ts +0 -994
  159. package/src/rabitq-hnsw/test/hnsw.test.ts +0 -1213
  160. /package/src/{rabitq-hnsw → rabitq-ivf}/src/rabitq.ts +0 -0
@@ -43,85 +43,83 @@
43
43
  * derives `conclusion` at an additional `cost`.
44
44
  */
45
45
  export interface Rule<I> {
46
- premises: readonly I[];
47
- conclusion: I;
48
- /** Local (edge) cost added on top of the premises' costs. Non-negative. */
49
- cost: number;
50
- /** The combinator this rule's firing uses at its conclusion:
51
- * • `"min"` (default, omitted) — Knuth/A* proper: the conclusion's cost is
52
- * the CHEAPEST of any rule that reaches it, every other route discarded.
53
- * The shortest-path monoid (min, +) that makes the search admissible and
54
- * output-sensitive.
55
- * • `"sum"` — evidence pooling: EVERY firing of a sum rule contributes its
56
- * cost to the SAME conclusion (accumulated in {@link
57
- * DeductionSystem.pool}), instead of competing to be the one cheapest
58
- * route. The (+, +) monoid a consensus vote needs — several
59
- * independent premises corroborating one conclusion — kept deliberately
60
- * OUT of the min-cost chart: a pooled conclusion is never relaxed into
61
- * `g`, never enters the agenda, and is never itself a premise — it is a
62
- * terminal aggregate the caller reads out of `pool` once the search is
63
- * done. */
64
- combine?: "min" | "sum";
46
+ premises: readonly I[];
47
+ conclusion: I;
48
+ /** Local (edge) cost added on top of the premises' costs. Non-negative. */
49
+ cost: number;
50
+ /** The combinator this rule's firing uses at its conclusion:
51
+ * • `"min"` (default, omitted) — Knuth/A* proper: the conclusion's cost is
52
+ * the CHEAPEST of any rule that reaches it, every other route discarded.
53
+ * The shortest-path monoid (min, +) that makes the search admissible and
54
+ * output-sensitive.
55
+ * • `"sum"` — evidence pooling: EVERY firing of a sum rule contributes its
56
+ * cost to the SAME conclusion (accumulated in {@link
57
+ * DeductionSystem.pool}), instead of competing to be the one cheapest
58
+ * route. The (+, +) monoid a consensus vote needs — several
59
+ * independent premises corroborating one conclusion — kept deliberately
60
+ * OUT of the min-cost chart: a pooled conclusion is never relaxed into
61
+ * `g`, never enters the agenda, and is never itself a premise — it is a
62
+ * terminal aggregate the caller reads out of `pool` once the search is
63
+ * done. */
64
+ combine?: "min" | "sum";
65
65
  }
66
66
  /** One rule's contribution to a pooled (`combine: "sum"`) conclusion — the
67
67
  * firing rule and the already-finalised derivations of its premises, so a
68
68
  * caller can render each contribution exactly as it would a min-cost step. */
69
69
  export interface PooledContribution<I> {
70
- rule: Rule<I>;
71
- premises: Array<Derivation<I>>;
70
+ rule: Rule<I>;
71
+ premises: Array<Derivation<I>>;
72
72
  }
73
73
  /** The running aggregate at one pooled conclusion: every sum-mode rule that
74
74
  * has fired for it, accumulated. */
75
75
  export interface PooledConclusion<I> {
76
- item: I;
77
- cost: number;
78
- contributions: Array<PooledContribution<I>>;
76
+ item: I;
77
+ cost: number;
78
+ contributions: Array<PooledContribution<I>>;
79
79
  }
80
80
  /** The problem the solver is given: items, rules, a goal, and a heuristic. */
81
81
  export interface DeductionSystem<I> {
82
- /** Canonical key for chart memoization (the item's boundary signature). */
83
- key(item: I): string;
84
- /** Axioms: the atomic items and their base costs (the search's seeds). */
85
- axioms(): Iterable<{
86
- item: I;
87
- cost: number;
88
- }>;
89
- /**
90
- * Lazily generate the demanded rules that have `item` among their premises.
91
- * Called once, when `item` is finalised. `costOf` returns the finalised cost
92
- * of any item (Infinity if not yet known) — use it for backward-demand /
93
- * boundary filtering, e.g. drop a rule whose other premises are still open or
94
- * whose conclusion can no longer beat the best goal.
95
- */
96
- rules(item: I, costOf: (other: I) => number): Iterable<Rule<I>>;
97
- /** Whether `item` satisfies the goal. The first finalised goal wins. */
98
- isGoal(item: I): boolean;
99
- /** Admissible, consistent lower bound on the cost from `item` to a goal. */
100
- heuristic?(item: I): number;
101
- /** Present only on a system that fires `combine: "sum"` rules — supplied
102
- * empty, populated in place as the search runs, read back once it returns
103
- * (typically `null`: a pooling system has no goal to reach, it exhausts its
104
- * axioms instead — see {@link lightestDerivation}). Absent on every
105
- * ordinary min-cost system, which is what keeps pooling a zero-cost opt-in:
106
- * `relax` only takes the pooling branch when a rule declares `combine:
107
- * "sum"` AND this map is present. */
108
- pool?: Map<string, PooledConclusion<I>>;
82
+ /** Canonical key for chart memoization (the item's boundary signature). */
83
+ key(item: I): string;
84
+ /** Axioms: the atomic items and their base costs (the search's seeds). */
85
+ axioms(): Iterable<{
86
+ item: I;
87
+ cost: number;
88
+ }>;
89
+ /**
90
+ * Lazily generate the demanded rules that have `item` among their premises.
91
+ * Called once, when `item` is finalised. `costOf` returns the finalised cost
92
+ * of any item (Infinity if not yet known) — use it for backward-demand /
93
+ * boundary filtering, e.g. drop a rule whose other premises are still open or
94
+ * whose conclusion can no longer beat the best goal.
95
+ */
96
+ rules(item: I, costOf: (other: I) => number): Iterable<Rule<I>>;
97
+ /** Whether `item` satisfies the goal. The first finalised goal wins. */
98
+ isGoal(item: I): boolean;
99
+ /** Admissible, consistent lower bound on the cost from `item` to a goal. */
100
+ heuristic?(item: I): number;
101
+ /** Present only on a system that fires `combine: "sum"` rules — supplied
102
+ * empty, populated in place as the search runs, read back once it returns
103
+ * (typically `null`: a pooling system has no goal to reach, it exhausts its
104
+ * axioms instead — see {@link lightestDerivation}). Absent on every
105
+ * ordinary min-cost system, which is what keeps pooling a zero-cost opt-in:
106
+ * `relax` only takes the pooling branch when a rule declares `combine:
107
+ * "sum"` AND this map is present. */
108
+ pool?: Map<string, PooledConclusion<I>>;
109
109
  }
110
110
  /** A node of the reconstructed derivation tree. */
111
111
  export interface Derivation<I> {
112
- /** The derived item. */
113
- item: I;
114
- /** This item's minimum derivation cost (its g value). */
115
- cost: number;
116
- /** The rule that produced it, or null if it is an axiom. */
117
- rule: Rule<I> | null;
118
- /** Derivations of the rule's premises (empty for an axiom). */
119
- premises: Array<Derivation<I>>;
112
+ /** The derived item. */
113
+ item: I;
114
+ /** This item's minimum derivation cost (its g value). */
115
+ cost: number;
116
+ /** The rule that produced it, or null if it is an axiom. */
117
+ rule: Rule<I> | null;
118
+ /** Derivations of the rule's premises (empty for an axiom). */
119
+ premises: Array<Derivation<I>>;
120
120
  }
121
121
  /**
122
122
  * Find a lightest derivation of a goal item, or `null` if none exists.
123
123
  * `cost` on the returned root is the total derivation cost.
124
124
  */
125
- export declare function lightestDerivation<I>(
126
- system: DeductionSystem<I>,
127
- ): Derivation<I> | null;
125
+ export declare function lightestDerivation<I>(system: DeductionSystem<I>): Derivation<I> | null;
@@ -44,118 +44,112 @@ import { MinHeap } from "./priority-queue.js";
44
44
  * `cost` on the returned root is the total derivation cost.
45
45
  */
46
46
  export function lightestDerivation(system) {
47
- const g = new Map(); // best known cost per item
48
- const proof = new Map(); // producing rule per item
49
- const items = new Map(); // key → the item it stands for
50
- const hCache = new Map();
51
- const agenda = new MinHeap();
52
- const heuristic = system.heuristic;
53
- const h = (item, key) => {
54
- if (!heuristic) {
55
- return 0;
56
- }
57
- let v = hCache.get(key);
58
- if (v === undefined) {
59
- v = heuristic(item);
60
- hCache.set(key, v);
61
- }
62
- return v;
63
- };
64
- const costOf = (item) => g.get(system.key(item)) ?? Infinity;
65
- const relax = (item, cost, rule) => {
66
- const key = system.key(item);
67
- if (rule?.combine === "sum" && system.pool) {
68
- // Evidence pooling: accumulate this firing rather than compete for the
69
- // cheapest see {@link Rule.combine}. The premises are already
70
- // finalised (the caller only relaxes a rule once every premise's cost
71
- // is known), so their derivations can be read back immediately.
72
- const premises = rule.premises.map((p) =>
73
- reconstruct(p, system, g, proof)
74
- );
75
- const prior = system.pool.get(key);
76
- system.pool.set(key, {
77
- item,
78
- cost: (prior?.cost ?? 0) + cost,
79
- contributions: [...(prior?.contributions ?? []), { rule, premises }],
80
- });
81
- return;
82
- }
83
- const current = g.get(key);
84
- if (current === undefined || cost < current) {
85
- g.set(key, cost);
86
- proof.set(key, rule);
87
- items.set(key, item);
88
- agenda.push(cost + h(item, key), { key, g: cost });
89
- }
90
- };
91
- for (const { item, cost } of system.axioms()) {
92
- relax(item, cost, null);
93
- }
94
- while (agenda.size > 0) {
95
- const { value } = agenda.pop();
96
- const key = value.key;
97
- // Lazy deletion: an entry is stale if a cheaper derivation has since been
98
- // recorded for the same item.
99
- if (value.g !== g.get(key)) {
100
- continue;
101
- }
102
- const item = items.get(key);
103
- if (system.isGoal(item)) {
104
- return reconstruct(item, system, g, proof);
105
- }
106
- for (const rule of system.rules(item, costOf)) {
107
- let sum = rule.cost;
108
- let ready = true;
109
- for (const p of rule.premises) {
110
- const pc = g.get(system.key(p));
111
- if (pc === undefined) {
112
- ready = false;
113
- break;
47
+ const g = new Map(); // best known cost per item
48
+ const proof = new Map(); // producing rule per item
49
+ const items = new Map(); // key → the item it stands for
50
+ const hCache = new Map();
51
+ const agenda = new MinHeap();
52
+ const heuristic = system.heuristic;
53
+ const h = (item, key) => {
54
+ if (!heuristic)
55
+ return 0;
56
+ let v = hCache.get(key);
57
+ if (v === undefined) {
58
+ v = heuristic(item);
59
+ hCache.set(key, v);
60
+ }
61
+ return v;
62
+ };
63
+ const costOf = (item) => g.get(system.key(item)) ?? Infinity;
64
+ const relax = (item, cost, rule) => {
65
+ const key = system.key(item);
66
+ if (rule?.combine === "sum" && system.pool) {
67
+ // Evidence pooling: accumulate this firing rather than compete for the
68
+ // cheapest see {@link Rule.combine}. The premises are already
69
+ // finalised (the caller only relaxes a rule once every premise's cost
70
+ // is known), so their derivations can be read back immediately.
71
+ const premises = rule.premises.map((p) => reconstruct(p, system, g, proof));
72
+ const prior = system.pool.get(key);
73
+ system.pool.set(key, {
74
+ item,
75
+ cost: (prior?.cost ?? 0) + cost,
76
+ contributions: [...(prior?.contributions ?? []), { rule, premises }],
77
+ });
78
+ return;
79
+ }
80
+ const current = g.get(key);
81
+ if (current === undefined || cost < current) {
82
+ g.set(key, cost);
83
+ proof.set(key, rule);
84
+ items.set(key, item);
85
+ agenda.push(cost + h(item, key), { key, g: cost });
86
+ }
87
+ };
88
+ for (const { item, cost } of system.axioms())
89
+ relax(item, cost, null);
90
+ while (agenda.size > 0) {
91
+ const { value } = agenda.pop();
92
+ const key = value.key;
93
+ // Lazy deletion: an entry is stale if a cheaper derivation has since been
94
+ // recorded for the same item.
95
+ if (value.g !== g.get(key))
96
+ continue;
97
+ const item = items.get(key);
98
+ if (system.isGoal(item)) {
99
+ return reconstruct(item, system, g, proof);
100
+ }
101
+ for (const rule of system.rules(item, costOf)) {
102
+ let sum = rule.cost;
103
+ let ready = true;
104
+ for (const p of rule.premises) {
105
+ const pc = g.get(system.key(p));
106
+ if (pc === undefined) {
107
+ ready = false;
108
+ break;
109
+ }
110
+ sum += pc;
111
+ }
112
+ if (ready)
113
+ relax(rule.conclusion, sum, rule);
114
114
  }
115
- sum += pc;
116
- }
117
- if (ready) {
118
- relax(rule.conclusion, sum, rule);
119
- }
120
115
  }
121
- }
122
- return null;
116
+ return null;
123
117
  }
124
118
  function reconstruct(item, system, g, proof) {
125
- // Iterative post-order over the derivation hypergraph. In the rewrite
126
- // search every rule has one premise, so the derivation is a chain whose
127
- // length equals the number of frontier edges — which, with long inputs,
128
- // can exceed the call stack. Multi-premise rules (the test-suite bridge
129
- // case) are handled by the same explicit stack.
130
- const done = new Map();
131
- const stack = [item];
132
- while (stack.length > 0) {
133
- const cur = stack[stack.length - 1]; // peek
134
- const key = system.key(cur);
135
- if (done.has(key)) {
136
- stack.pop();
137
- continue;
138
- }
139
- const rule = proof.get(key) ?? null;
140
- const premises = rule?.premises ?? [];
141
- // Push any unresolved premises (rightmost first → leftmost resolves first).
142
- let pending = false;
143
- for (let i = premises.length - 1; i >= 0; i--) {
144
- if (!done.has(system.key(premises[i]))) {
145
- stack.push(premises[i]);
146
- pending = true;
147
- }
148
- }
149
- if (!pending) {
150
- stack.pop(); // this item
151
- const kids = premises.map((p) => done.get(system.key(p)));
152
- done.set(key, {
153
- item: cur,
154
- cost: g.get(key),
155
- rule,
156
- premises: kids,
157
- });
119
+ // Iterative post-order over the derivation hypergraph. In the rewrite
120
+ // search every rule has one premise, so the derivation is a chain whose
121
+ // length equals the number of frontier edges — which, with long inputs,
122
+ // can exceed the call stack. Multi-premise rules (the test-suite bridge
123
+ // case) are handled by the same explicit stack.
124
+ const done = new Map();
125
+ const stack = [item];
126
+ while (stack.length > 0) {
127
+ const cur = stack[stack.length - 1]; // peek
128
+ const key = system.key(cur);
129
+ if (done.has(key)) {
130
+ stack.pop();
131
+ continue;
132
+ }
133
+ const rule = proof.get(key) ?? null;
134
+ const premises = rule?.premises ?? [];
135
+ // Push any unresolved premises (rightmost first → leftmost resolves first).
136
+ let pending = false;
137
+ for (let i = premises.length - 1; i >= 0; i--) {
138
+ if (!done.has(system.key(premises[i]))) {
139
+ stack.push(premises[i]);
140
+ pending = true;
141
+ }
142
+ }
143
+ if (!pending) {
144
+ stack.pop(); // this item
145
+ const kids = premises.map((p) => done.get(system.key(p)));
146
+ done.set(key, {
147
+ item: cur,
148
+ cost: g.get(key),
149
+ rule,
150
+ premises: kids,
151
+ });
152
+ }
158
153
  }
159
- }
160
- return done.get(system.key(item));
154
+ return done.get(system.key(item));
161
155
  }
@@ -1,11 +1,5 @@
1
1
  export { lightestDerivation } from "./deduction.js";
2
- export type {
3
- DeductionSystem,
4
- Derivation,
5
- PooledConclusion,
6
- PooledContribution,
7
- Rule,
8
- } from "./deduction.js";
2
+ export type { DeductionSystem, Derivation, PooledConclusion, PooledContribution, Rule, } from "./deduction.js";
9
3
  export { coverSequence } from "./rewrite.js";
10
4
  export type { CandidateSpan, Cover } from "./rewrite.js";
11
5
  export { Trie } from "./trie.js";
@@ -9,12 +9,12 @@
9
9
  * of objects) keep the hot path allocation-free.
10
10
  */
11
11
  export declare class MinHeap<T> {
12
- private readonly keys;
13
- private readonly vals;
14
- get size(): number;
15
- push(priority: number, value: T): void;
16
- pop(): {
17
- priority: number;
18
- value: T;
19
- } | undefined;
12
+ private readonly keys;
13
+ private readonly vals;
14
+ get size(): number;
15
+ push(priority: number, value: T): void;
16
+ pop(): {
17
+ priority: number;
18
+ value: T;
19
+ } | undefined;
20
20
  }
@@ -9,69 +9,65 @@
9
9
  * of objects) keep the hot path allocation-free.
10
10
  */
11
11
  export class MinHeap {
12
- keys = [];
13
- vals = [];
14
- get size() {
15
- return this.keys.length;
16
- }
17
- push(priority, value) {
18
- const keys = this.keys;
19
- const vals = this.vals;
20
- let i = keys.length;
21
- keys.push(priority);
22
- vals.push(value);
23
- while (i > 0) {
24
- const parent = (i - 1) >> 1;
25
- if (keys[i] < keys[parent]) {
26
- const tk = keys[i];
27
- keys[i] = keys[parent];
28
- keys[parent] = tk;
29
- const tv = vals[i];
30
- vals[i] = vals[parent];
31
- vals[parent] = tv;
32
- i = parent;
33
- } else {
34
- break;
35
- }
12
+ keys = [];
13
+ vals = [];
14
+ get size() {
15
+ return this.keys.length;
36
16
  }
37
- }
38
- pop() {
39
- const keys = this.keys;
40
- const vals = this.vals;
41
- const n = keys.length;
42
- if (n === 0) {
43
- return undefined;
44
- }
45
- const top = { priority: keys[0], value: vals[0] };
46
- const lastKey = keys.pop();
47
- const lastVal = vals.pop();
48
- const m = keys.length;
49
- if (m > 0) {
50
- keys[0] = lastKey;
51
- vals[0] = lastVal;
52
- let i = 0;
53
- for (;;) {
54
- const left = 2 * i + 1;
55
- const right = left + 1;
56
- let best = i;
57
- if (left < m && keys[left] < keys[best]) {
58
- best = left;
59
- }
60
- if (right < m && keys[right] < keys[best]) {
61
- best = right;
17
+ push(priority, value) {
18
+ const keys = this.keys;
19
+ const vals = this.vals;
20
+ let i = keys.length;
21
+ keys.push(priority);
22
+ vals.push(value);
23
+ while (i > 0) {
24
+ const parent = (i - 1) >> 1;
25
+ if (keys[i] < keys[parent]) {
26
+ const tk = keys[i];
27
+ keys[i] = keys[parent];
28
+ keys[parent] = tk;
29
+ const tv = vals[i];
30
+ vals[i] = vals[parent];
31
+ vals[parent] = tv;
32
+ i = parent;
33
+ }
34
+ else
35
+ break;
62
36
  }
63
- if (best === i) {
64
- break;
37
+ }
38
+ pop() {
39
+ const keys = this.keys;
40
+ const vals = this.vals;
41
+ const n = keys.length;
42
+ if (n === 0)
43
+ return undefined;
44
+ const top = { priority: keys[0], value: vals[0] };
45
+ const lastKey = keys.pop();
46
+ const lastVal = vals.pop();
47
+ const m = keys.length;
48
+ if (m > 0) {
49
+ keys[0] = lastKey;
50
+ vals[0] = lastVal;
51
+ let i = 0;
52
+ for (;;) {
53
+ const left = 2 * i + 1;
54
+ const right = left + 1;
55
+ let best = i;
56
+ if (left < m && keys[left] < keys[best])
57
+ best = left;
58
+ if (right < m && keys[right] < keys[best])
59
+ best = right;
60
+ if (best === i)
61
+ break;
62
+ const tk = keys[i];
63
+ keys[i] = keys[best];
64
+ keys[best] = tk;
65
+ const tv = vals[i];
66
+ vals[i] = vals[best];
67
+ vals[best] = tv;
68
+ i = best;
69
+ }
65
70
  }
66
- const tk = keys[i];
67
- keys[i] = keys[best];
68
- keys[best] = tk;
69
- const tv = vals[i];
70
- vals[i] = vals[best];
71
- vals[best] = tv;
72
- i = best;
73
- }
71
+ return top;
74
72
  }
75
- return top;
76
- }
77
73
  }
@@ -21,22 +21,22 @@
21
21
  */
22
22
  /** A candidate span over a sequence, carrying caller payload. */
23
23
  export interface CandidateSpan<P> {
24
- /** Start offset (inclusive). */
25
- start: number;
26
- /** End offset (exclusive); must be > start. */
27
- end: number;
28
- /** Relative cost of using this span (default 1). Lower wins ties. */
29
- weight?: number;
30
- /** Caller data, returned on the chosen spans. */
31
- payload: P;
24
+ /** Start offset (inclusive). */
25
+ start: number;
26
+ /** End offset (exclusive); must be > start. */
27
+ end: number;
28
+ /** Relative cost of using this span (default 1). Lower wins ties. */
29
+ weight?: number;
30
+ /** Caller data, returned on the chosen spans. */
31
+ payload: P;
32
32
  }
33
33
  export interface Cover<P> {
34
- /** Chosen non-overlapping spans, left to right. */
35
- spans: Array<CandidateSpan<P>>;
36
- /** Symbols covered by the chosen spans. */
37
- covered: number;
38
- /** Symbols left uncovered. */
39
- uncovered: number;
34
+ /** Chosen non-overlapping spans, left to right. */
35
+ spans: Array<CandidateSpan<P>>;
36
+ /** Symbols covered by the chosen spans. */
37
+ covered: number;
38
+ /** Symbols left uncovered. */
39
+ uncovered: number;
40
40
  }
41
41
  /**
42
42
  * The lightest non-overlapping cover of `[0, length)` drawn from `candidates`.
@@ -53,7 +53,4 @@ export interface Cover<P> {
53
53
  * items, each finalised once, with one "skip" edge plus the candidates that
54
54
  * start there. No quadratic span structure.
55
55
  */
56
- export declare function coverSequence<P>(
57
- length: number,
58
- candidates: ReadonlyArray<CandidateSpan<P>>,
59
- ): Cover<P>;
56
+ export declare function coverSequence<P>(length: number, candidates: ReadonlyArray<CandidateSpan<P>>): Cover<P>;