@hviana/sema 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/example/demo.js +25 -25
- package/dist/example/train_base.d.ts +21 -19
- package/dist/example/train_base.js +1952 -1684
- package/dist/src/alphabet.d.ts +3 -3
- package/dist/src/alphabet.js +27 -24
- package/dist/src/alu/src/alu.d.ts +194 -169
- package/dist/src/alu/src/alu.js +414 -374
- package/dist/src/alu/src/expr.d.ts +43 -36
- package/dist/src/alu/src/expr.js +278 -252
- package/dist/src/alu/src/index.d.ts +98 -9
- package/dist/src/alu/src/index.js +63 -9
- package/dist/src/alu/src/kernel-arith.d.ts +5 -1
- package/dist/src/alu/src/kernel-arith.js +285 -195
- package/dist/src/alu/src/kernel-bits.d.ts +5 -1
- package/dist/src/alu/src/kernel-bits.js +115 -81
- package/dist/src/alu/src/kernel-logic.js +63 -33
- package/dist/src/alu/src/kernel-nd.js +195 -155
- package/dist/src/alu/src/kernel-numeric.d.ts +80 -16
- package/dist/src/alu/src/kernel-numeric.js +331 -259
- package/dist/src/alu/src/operation.d.ts +132 -112
- package/dist/src/alu/src/operation.js +163 -149
- package/dist/src/alu/src/parser.d.ts +175 -168
- package/dist/src/alu/src/parser.js +421 -382
- package/dist/src/alu/src/resonance.d.ts +25 -16
- package/dist/src/alu/src/resonance.js +56 -49
- package/dist/src/alu/src/text.d.ts +7 -3
- package/dist/src/alu/src/text.js +37 -31
- package/dist/src/alu/src/value.d.ts +14 -14
- package/dist/src/alu/src/value.js +160 -150
- package/dist/src/alu/test/alu.test.js +656 -543
- package/dist/src/bytes.d.ts +5 -1
- package/dist/src/bytes.js +40 -33
- package/dist/src/config.d.ts +102 -102
- package/dist/src/config.js +83 -83
- package/dist/src/derive/src/deduction.d.ts +62 -60
- package/dist/src/derive/src/deduction.js +109 -103
- package/dist/src/derive/src/index.d.ts +7 -1
- package/dist/src/derive/src/priority-queue.d.ts +8 -8
- package/dist/src/derive/src/priority-queue.js +61 -57
- package/dist/src/derive/src/rewrite.d.ts +18 -15
- package/dist/src/derive/src/rewrite.js +67 -59
- package/dist/src/derive/src/trie.d.ts +56 -56
- package/dist/src/derive/src/trie.js +179 -175
- package/dist/src/derive/test/derive.test.js +100 -96
- package/dist/src/extension.d.ts +16 -13
- package/dist/src/geometry.d.ts +42 -17
- package/dist/src/geometry.js +266 -235
- package/dist/src/index.d.ts +17 -2
- package/dist/src/index.js +7 -1
- package/dist/src/ingest-cache.d.ts +30 -25
- package/dist/src/ingest-cache.js +127 -108
- package/dist/src/mind/articulation.d.ts +5 -1
- package/dist/src/mind/articulation.js +112 -77
- package/dist/src/mind/attention.d.ts +108 -40
- package/dist/src/mind/attention.js +871 -749
- package/dist/src/mind/canonical.d.ts +19 -4
- package/dist/src/mind/canonical.js +31 -27
- package/dist/src/mind/graph-search.d.ts +225 -201
- package/dist/src/mind/graph-search.js +821 -742
- package/dist/src/mind/index.d.ts +10 -2
- package/dist/src/mind/junction.d.ts +58 -31
- package/dist/src/mind/junction.js +237 -172
- package/dist/src/mind/learning.d.ts +52 -16
- package/dist/src/mind/learning.js +165 -143
- package/dist/src/mind/match.d.ts +69 -20
- package/dist/src/mind/match.js +318 -259
- package/dist/src/mind/mechanisms/alu.js +16 -16
- package/dist/src/mind/mechanisms/cast.d.ts +13 -9
- package/dist/src/mind/mechanisms/cast.js +456 -363
- package/dist/src/mind/mechanisms/confluence.d.ts +12 -8
- package/dist/src/mind/mechanisms/confluence.js +183 -152
- package/dist/src/mind/mechanisms/cover.d.ts +8 -2
- package/dist/src/mind/mechanisms/cover.js +210 -148
- package/dist/src/mind/mechanisms/extraction.d.ts +34 -8
- package/dist/src/mind/mechanisms/extraction.js +288 -234
- package/dist/src/mind/mechanisms/recall.d.ts +10 -6
- package/dist/src/mind/mechanisms/recall.js +185 -126
- package/dist/src/mind/mind.d.ts +154 -129
- package/dist/src/mind/mind.js +288 -258
- package/dist/src/mind/pipeline-mechanism.d.ts +124 -112
- package/dist/src/mind/pipeline-mechanism.js +172 -161
- package/dist/src/mind/pipeline.d.ts +14 -4
- package/dist/src/mind/pipeline.js +189 -125
- package/dist/src/mind/primitives.d.ts +32 -8
- package/dist/src/mind/primitives.js +117 -99
- package/dist/src/mind/rationale.d.ts +98 -86
- package/dist/src/mind/rationale.js +121 -113
- package/dist/src/mind/reasoning.d.ts +13 -2
- package/dist/src/mind/reasoning.js +166 -129
- package/dist/src/mind/recognition.d.ts +4 -1
- package/dist/src/mind/recognition.js +208 -183
- package/dist/src/mind/resonance.d.ts +22 -5
- package/dist/src/mind/resonance.js +0 -0
- package/dist/src/mind/trace.d.ts +25 -6
- package/dist/src/mind/trace.js +58 -50
- package/dist/src/mind/traverse.d.ts +58 -16
- package/dist/src/mind/traverse.js +357 -304
- package/dist/src/mind/types.d.ts +127 -120
- package/dist/src/mind/types.js +69 -60
- package/dist/src/rabitq-hnsw/src/database.d.ts +179 -177
- package/dist/src/rabitq-hnsw/src/database.js +359 -342
- package/dist/src/rabitq-hnsw/src/heap.d.ts +12 -12
- package/dist/src/rabitq-hnsw/src/heap.js +80 -75
- package/dist/src/rabitq-hnsw/src/hnsw.d.ts +103 -103
- package/dist/src/rabitq-hnsw/src/hnsw.js +454 -428
- package/dist/src/rabitq-hnsw/src/index.d.ts +6 -1
- package/dist/src/rabitq-hnsw/src/prng.d.ts +10 -10
- package/dist/src/rabitq-hnsw/src/prng.js +27 -25
- package/dist/src/rabitq-hnsw/src/rabitq.d.ts +69 -69
- package/dist/src/rabitq-hnsw/src/rabitq.js +262 -246
- package/dist/src/rabitq-hnsw/src/store.d.ts +132 -132
- package/dist/src/rabitq-hnsw/src/store.js +843 -752
- package/dist/src/rabitq-hnsw/test/hnsw.test.js +1054 -805
- package/dist/src/sema.d.ts +13 -9
- package/dist/src/sema.js +40 -26
- package/dist/src/store-sqlite.d.ts +166 -144
- package/dist/src/store-sqlite.js +660 -578
- package/dist/src/store.d.ts +630 -593
- package/dist/src/store.js +1581 -1440
- package/dist/src/vec.d.ts +9 -5
- package/dist/src/vec.js +73 -61
- package/package.json +2 -2
package/dist/src/mind/index.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
export { Mind } from "./mind.js";
|
|
2
2
|
export type { Input, Response } from "./mind.js";
|
|
3
3
|
export type { ComputedSpan, ExtensionHost } from "./mind.js";
|
|
4
|
-
export type {
|
|
5
|
-
|
|
4
|
+
export type {
|
|
5
|
+
MechanismResult,
|
|
6
|
+
PipelineMechanism,
|
|
7
|
+
Precomputed,
|
|
8
|
+
} from "./pipeline-mechanism.js";
|
|
9
|
+
export type {
|
|
10
|
+
InspectRationale,
|
|
11
|
+
RationaleItem,
|
|
12
|
+
RationaleStep,
|
|
13
|
+
} from "./rationale.js";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { MindContext } from "./types.js";
|
|
2
2
|
export interface Junction {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
/** The node whose learnt bytes evidence this junction (a container form,
|
|
4
|
+
* a continuation, or a context). */
|
|
5
|
+
id: number;
|
|
6
|
+
/** The bytes that belong between left and right. */
|
|
7
|
+
interior: Uint8Array;
|
|
8
8
|
}
|
|
9
9
|
/** Seed node ids to ascend from for one side of a junction: the side's own
|
|
10
10
|
* node when it is a stored form, plus — when the node has no structural
|
|
@@ -15,7 +15,10 @@ export interface Junction {
|
|
|
15
15
|
* the window-id path is only taken when the node alone cannot ascend.
|
|
16
16
|
* Exported for callers (synonym junctions) that hold one side FIXED across
|
|
17
17
|
* several calls and so compute its seeds once instead of per call. */
|
|
18
|
-
export declare function junctionSeeds(
|
|
18
|
+
export declare function junctionSeeds(
|
|
19
|
+
ctx: MindContext,
|
|
20
|
+
b: Uint8Array,
|
|
21
|
+
): number[];
|
|
19
22
|
/** Per-response cache of the identity walks' pure reads (capped bytes,
|
|
20
23
|
* parent pages, container pages), keyed by the response lifecycle object
|
|
21
24
|
* (ctx.climbMemo). One response issues many walks whose ancestries overlap
|
|
@@ -24,17 +27,22 @@ export declare function junctionSeeds(ctx: MindContext, b: Uint8Array): number[]
|
|
|
24
27
|
* so every one of these reads is a pure function of the id — repeats cost a
|
|
25
28
|
* Map hit instead of a SQL statement or a byte reconstruction. */
|
|
26
29
|
export interface WalkCache {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
/** id → prefix bytes read so far + whether they are the COMPLETE bytes
|
|
31
|
+
* (shorter than the cap that read them). */
|
|
32
|
+
reads: Map<number, {
|
|
33
|
+
b: Uint8Array;
|
|
34
|
+
complete: boolean;
|
|
35
|
+
}>;
|
|
36
|
+
parents: Map<number, number[]>;
|
|
37
|
+
containers: Map<number, number[]>;
|
|
35
38
|
}
|
|
36
39
|
export declare function walkCache(ctx: MindContext): WalkCache | null;
|
|
37
|
-
export declare function cachedRead(
|
|
40
|
+
export declare function cachedRead(
|
|
41
|
+
ctx: MindContext,
|
|
42
|
+
cache: WalkCache | null,
|
|
43
|
+
id: number,
|
|
44
|
+
cap: number,
|
|
45
|
+
): Uint8Array;
|
|
38
46
|
/** Tier 1 body, parameterised on already-resolved seed lists so a caller
|
|
39
47
|
* holding one side FIXED across several calls (synonym junctions) pays for
|
|
40
48
|
* that side's seeds once, not once per call. The byte-containment check
|
|
@@ -59,26 +67,39 @@ export declare function cachedRead(ctx: MindContext, cache: WalkCache | null, id
|
|
|
59
67
|
* • per-node hub guards — parent fan-outs beyond √N are hubs (not
|
|
60
68
|
* expanded); each node contributes at most one √N page of containers;
|
|
61
69
|
* √N collected candidates decide. */
|
|
62
|
-
export declare function junctionContainersFrom(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
export declare function junctionContainersFrom(
|
|
71
|
+
ctx: MindContext,
|
|
72
|
+
left: Uint8Array,
|
|
73
|
+
right: Uint8Array,
|
|
74
|
+
maxContainer: number,
|
|
75
|
+
leftSeeds: number[],
|
|
76
|
+
rightSeeds: number[],
|
|
77
|
+
/** Shared expansion budget — a TIER's √N pops, not each walk's, when one
|
|
78
|
+
* tier issues several walks (synonym junctions try up to 2·haloQueryK
|
|
79
|
+
* siblings; without a shared budget each sibling would spend its own √N). */
|
|
80
|
+
budget?: {
|
|
67
81
|
n: number;
|
|
68
|
-
},
|
|
69
|
-
/** ORDER-FREE containment: also accept containers holding right-then-left.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
unordered?: boolean
|
|
82
|
+
},
|
|
83
|
+
/** ORDER-FREE containment: also accept containers holding right-then-left.
|
|
84
|
+
* A junction is evidence that the two forms were LEARNT TOGETHER; which
|
|
85
|
+
* one the query happened to mention first is a fact about the query, not
|
|
86
|
+
* about the learnt whole. The walk is identical (the seed ascent does not
|
|
87
|
+
* depend on order) — only the byte-containment test gains a second probe,
|
|
88
|
+
* so order-freedom costs two indexOf calls per visited node, never a
|
|
89
|
+
* second walk. */
|
|
90
|
+
unordered?: boolean,
|
|
91
|
+
): Junction[];
|
|
77
92
|
/** Tier 1 entry point: every learnt whole that literally contains
|
|
78
93
|
* left-then-right, found by ascending the structural DAG (parents +
|
|
79
94
|
* containment links) from the two sides' content-addressed identities.
|
|
80
95
|
* Both sides' seeds resolved fresh, one call. */
|
|
81
|
-
export declare function junctionContainers(
|
|
96
|
+
export declare function junctionContainers(
|
|
97
|
+
ctx: MindContext,
|
|
98
|
+
left: Uint8Array,
|
|
99
|
+
right: Uint8Array,
|
|
100
|
+
maxContainer: number,
|
|
101
|
+
unordered?: boolean,
|
|
102
|
+
): Junction[];
|
|
82
103
|
/** Tier 2.5: synonym junctions — the container ascent (tier 1) applied to
|
|
83
104
|
* halo siblings of left and right. When a distributional synonym of one
|
|
84
105
|
* form participates in a learnt whole with the other form, the container
|
|
@@ -92,4 +113,10 @@ export declare function junctionContainers(ctx: MindContext, left: Uint8Array, r
|
|
|
92
113
|
* cost is bounded at √N·W pops total regardless of how many siblings are
|
|
93
114
|
* tried. A sibling whose bytes exceed `maxInterior` is skipped (it
|
|
94
115
|
* cannot be junction-sized). */
|
|
95
|
-
export declare function junctionSynonyms(
|
|
116
|
+
export declare function junctionSynonyms(
|
|
117
|
+
ctx: MindContext,
|
|
118
|
+
left: Uint8Array,
|
|
119
|
+
right: Uint8Array,
|
|
120
|
+
maxInterior: number,
|
|
121
|
+
unordered?: boolean,
|
|
122
|
+
): Promise<Junction[]>;
|
|
@@ -26,59 +26,69 @@ import { indexOf } from "../bytes.js";
|
|
|
26
26
|
* Exported for callers (synonym junctions) that hold one side FIXED across
|
|
27
27
|
* several calls and so compute its seeds once instead of per call. */
|
|
28
28
|
export function junctionSeeds(ctx, b) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const wids = [...windowIds(ctx, b).values()];
|
|
34
|
-
return [r, ...wids];
|
|
29
|
+
const r = resolve(ctx, b);
|
|
30
|
+
if (r !== null) {
|
|
31
|
+
if (ctx.store.parentsFirst(r, 1).length > 0) {
|
|
32
|
+
return [r];
|
|
35
33
|
}
|
|
36
34
|
const wids = [...windowIds(ctx, b).values()];
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
return [r, ...wids];
|
|
36
|
+
}
|
|
37
|
+
const wids = [...windowIds(ctx, b).values()];
|
|
38
|
+
if (wids.length <= 2) {
|
|
39
|
+
return wids;
|
|
40
|
+
}
|
|
41
|
+
return [wids[0], wids[wids.length - 1]];
|
|
40
42
|
}
|
|
41
43
|
const walkCaches = new WeakMap();
|
|
42
44
|
export function walkCache(ctx) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
if (ctx.climbMemo === null) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
let c = walkCaches.get(ctx.climbMemo);
|
|
49
|
+
if (c === undefined) {
|
|
50
|
+
walkCaches.set(
|
|
51
|
+
ctx.climbMemo,
|
|
52
|
+
c = { reads: new Map(), parents: new Map(), containers: new Map() },
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return c;
|
|
50
56
|
}
|
|
51
57
|
export function cachedRead(ctx, cache, id, cap) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
if (cache === null) {
|
|
59
|
+
return read(ctx, id, cap + 1);
|
|
60
|
+
}
|
|
61
|
+
const hit = cache.reads.get(id);
|
|
62
|
+
// A cached COMPLETE read serves any cap; a cached truncated read serves
|
|
63
|
+
// any cap it already covers (the caller only checks `length > cap`).
|
|
64
|
+
if (hit !== undefined && (hit.complete || hit.b.length > cap)) {
|
|
65
|
+
return hit.b;
|
|
66
|
+
}
|
|
67
|
+
const b = read(ctx, id, cap + 1);
|
|
68
|
+
cache.reads.set(id, { b, complete: b.length <= cap });
|
|
69
|
+
return b;
|
|
62
70
|
}
|
|
63
71
|
function cachedParents(ctx, cache, id, limit) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
if (cache === null) {
|
|
73
|
+
return ctx.store.parentsFirst(id, limit);
|
|
74
|
+
}
|
|
75
|
+
let v = cache.parents.get(id);
|
|
76
|
+
if (v === undefined) {
|
|
77
|
+
v = ctx.store.parentsFirst(id, limit);
|
|
78
|
+
cache.parents.set(id, v);
|
|
79
|
+
}
|
|
80
|
+
return v;
|
|
72
81
|
}
|
|
73
82
|
function cachedContainers(ctx, cache, id, limit) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
if (cache === null) {
|
|
84
|
+
return ctx.store.containersSlice(id, 0, limit);
|
|
85
|
+
}
|
|
86
|
+
let v = cache.containers.get(id);
|
|
87
|
+
if (v === undefined) {
|
|
88
|
+
v = ctx.store.containersSlice(id, 0, limit);
|
|
89
|
+
cache.containers.set(id, v);
|
|
90
|
+
}
|
|
91
|
+
return v;
|
|
82
92
|
}
|
|
83
93
|
/** Tier 1 body, parameterised on already-resolved seed lists so a caller
|
|
84
94
|
* holding one side FIXED across several calls (synonym junctions) pays for
|
|
@@ -104,113 +114,139 @@ function cachedContainers(ctx, cache, id, limit) {
|
|
|
104
114
|
* • per-node hub guards — parent fan-outs beyond √N are hubs (not
|
|
105
115
|
* expanded); each node contributes at most one √N page of containers;
|
|
106
116
|
* √N collected candidates decide. */
|
|
107
|
-
export function junctionContainersFrom(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
117
|
+
export function junctionContainersFrom(
|
|
118
|
+
ctx,
|
|
119
|
+
left,
|
|
120
|
+
right,
|
|
121
|
+
maxContainer,
|
|
122
|
+
leftSeeds,
|
|
123
|
+
rightSeeds,
|
|
124
|
+
/** Shared expansion budget — a TIER's √N pops, not each walk's, when one
|
|
125
|
+
* tier issues several walks (synonym junctions try up to 2·haloQueryK
|
|
126
|
+
* siblings; without a shared budget each sibling would spend its own √N). */
|
|
127
|
+
budget,
|
|
128
|
+
/** ORDER-FREE containment: also accept containers holding right-then-left.
|
|
129
|
+
* A junction is evidence that the two forms were LEARNT TOGETHER; which
|
|
130
|
+
* one the query happened to mention first is a fact about the query, not
|
|
131
|
+
* about the learnt whole. The walk is identical (the seed ascent does not
|
|
132
|
+
* depend on order) — only the byte-containment test gains a second probe,
|
|
133
|
+
* so order-freedom costs two indexOf calls per visited node, never a
|
|
134
|
+
* second walk. */
|
|
135
|
+
unordered = false,
|
|
136
|
+
) {
|
|
137
|
+
const bound = hubBound(ctx);
|
|
138
|
+
const joinedLength = left.length + right.length;
|
|
139
|
+
const seeds = [...new Set([...leftSeeds, ...rightSeeds])];
|
|
140
|
+
if (seeds.length === 0) {
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
const b = budget ?? { n: bound * ctx.space.maxGroup };
|
|
144
|
+
// DEPTH CAP: perception trees are W-ary and a junction container is
|
|
145
|
+
// phrase-scale, so it sits within ~log_W(maxContainer) structural levels
|
|
146
|
+
// of its parts — at most W levels for any practical W (plus the
|
|
147
|
+
// containment hop the seeds already are). Ancestry beyond that depth is
|
|
148
|
+
// strictly larger than any admissible container; walking it can only burn
|
|
149
|
+
// budget, never find a junction.
|
|
150
|
+
const maxDepth = ctx.space.maxGroup;
|
|
151
|
+
const out = [];
|
|
152
|
+
const cache = walkCache(ctx);
|
|
153
|
+
const seen = new Set(seeds);
|
|
154
|
+
const stack = seeds.map((id) => ({
|
|
155
|
+
id,
|
|
156
|
+
d: 0,
|
|
157
|
+
}));
|
|
158
|
+
while (stack.length > 0 && out.length < bound && b.n-- > 0) {
|
|
159
|
+
const { id: x, d } = stack.pop();
|
|
160
|
+
const f = cachedRead(ctx, cache, x, maxContainer);
|
|
161
|
+
if (f.length > maxContainer) {
|
|
162
|
+
continue; // beyond phrase scale: prune branch
|
|
163
|
+
}
|
|
164
|
+
if (unordered) {
|
|
165
|
+
// Order-free containment does NOT require disjoint occurrences: two
|
|
166
|
+
// grid-aligned fragments of the same whole legitimately OVERLAP inside
|
|
167
|
+
// it ("red " at 0 and " cir" at 3 in `red circle`), and both being
|
|
168
|
+
// literal substrings is the evidence. The interior is the gap between
|
|
169
|
+
// them when they are disjoint, empty otherwise. Only the containment
|
|
170
|
+
// test differs from the ordered form — and because occurrences may
|
|
171
|
+
// overlap or abut, `f.length > joinedLength` is too strict (grid
|
|
172
|
+
// fragments of one whole sum past it; "red " + "circle" exactly equals
|
|
173
|
+
// `red circle`). The container must be a STRICT super-form of each
|
|
174
|
+
// side, so that holding both is more than restating either.
|
|
175
|
+
const li = indexOf(f, left, 0);
|
|
176
|
+
const ri = li >= 0 ? indexOf(f, right, 0) : -1;
|
|
177
|
+
if (
|
|
178
|
+
li >= 0 && ri >= 0 && f.length > Math.max(left.length, right.length)
|
|
179
|
+
) {
|
|
180
|
+
const lo = Math.min(li + left.length, ri + right.length);
|
|
181
|
+
const hi = Math.max(li, ri);
|
|
182
|
+
out.push({
|
|
183
|
+
id: x,
|
|
184
|
+
interior: lo < hi ? f.subarray(lo, hi) : f.subarray(0, 0),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
} else if (f.length > joinedLength) {
|
|
188
|
+
const li = indexOf(f, left, 0);
|
|
189
|
+
if (li >= 0) {
|
|
190
|
+
const ri = indexOf(f, right, li + left.length);
|
|
191
|
+
if (ri >= 0) {
|
|
192
|
+
out.push({ id: x, interior: f.subarray(li + left.length, ri) });
|
|
175
193
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (d >= maxDepth) {
|
|
197
|
+
continue; // deeper ancestry is beyond phrase scale
|
|
198
|
+
}
|
|
199
|
+
const parents = cachedParents(ctx, cache, x, bound + 1);
|
|
200
|
+
if (parents.length <= bound) { // beyond √N parents: a hub, not expanded
|
|
201
|
+
for (const p of parents) {
|
|
202
|
+
if (!seen.has(p)) {
|
|
203
|
+
seen.add(p);
|
|
204
|
+
stack.push({ id: p, d: d + 1 });
|
|
186
205
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Containment fan-out under the SAME hub reading as parents: a node
|
|
209
|
+
// whose containers fill a whole √N page is COMMON content — its
|
|
210
|
+
// containment ancestry reaches a non-discriminative slice of the corpus
|
|
211
|
+
// (the climb's saturation semantics), and walking it would spend the
|
|
212
|
+
// entire budget discovering nothing a junction could use. Such a node
|
|
213
|
+
// is not expanded through containment; a pair whose sides are common
|
|
214
|
+
// abstains here in a handful of pops and falls through to the resonance
|
|
215
|
+
// tier. Below the page bound the read IS the full container list, so
|
|
216
|
+
// the walk stays exact exactly where identity evidence discriminates.
|
|
217
|
+
const containers = cachedContainers(ctx, cache, x, bound);
|
|
218
|
+
if (containers.length < bound) {
|
|
219
|
+
for (const c of containers) {
|
|
220
|
+
if (!seen.has(c)) {
|
|
221
|
+
seen.add(c);
|
|
222
|
+
stack.push({ id: c, d: d + 1 });
|
|
204
223
|
}
|
|
224
|
+
}
|
|
205
225
|
}
|
|
206
|
-
|
|
226
|
+
}
|
|
227
|
+
return out;
|
|
207
228
|
}
|
|
208
229
|
/** Tier 1 entry point: every learnt whole that literally contains
|
|
209
230
|
* left-then-right, found by ascending the structural DAG (parents +
|
|
210
231
|
* containment links) from the two sides' content-addressed identities.
|
|
211
232
|
* Both sides' seeds resolved fresh, one call. */
|
|
212
|
-
export function junctionContainers(
|
|
213
|
-
|
|
233
|
+
export function junctionContainers(
|
|
234
|
+
ctx,
|
|
235
|
+
left,
|
|
236
|
+
right,
|
|
237
|
+
maxContainer,
|
|
238
|
+
unordered = false,
|
|
239
|
+
) {
|
|
240
|
+
return junctionContainersFrom(
|
|
241
|
+
ctx,
|
|
242
|
+
left,
|
|
243
|
+
right,
|
|
244
|
+
maxContainer,
|
|
245
|
+
junctionSeeds(ctx, left),
|
|
246
|
+
junctionSeeds(ctx, right),
|
|
247
|
+
undefined,
|
|
248
|
+
unordered,
|
|
249
|
+
);
|
|
214
250
|
}
|
|
215
251
|
/** Tier 2.5: synonym junctions — the container ascent (tier 1) applied to
|
|
216
252
|
* halo siblings of left and right. When a distributional synonym of one
|
|
@@ -225,38 +261,67 @@ export function junctionContainers(ctx, left, right, maxContainer, unordered = f
|
|
|
225
261
|
* cost is bounded at √N·W pops total regardless of how many siblings are
|
|
226
262
|
* tried. A sibling whose bytes exceed `maxInterior` is skipped (it
|
|
227
263
|
* cannot be junction-sized). */
|
|
228
|
-
export async function junctionSynonyms(
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
264
|
+
export async function junctionSynonyms(
|
|
265
|
+
ctx,
|
|
266
|
+
left,
|
|
267
|
+
right,
|
|
268
|
+
maxInterior,
|
|
269
|
+
unordered = false,
|
|
270
|
+
) {
|
|
271
|
+
const out = [];
|
|
272
|
+
const lId = resolve(ctx, left);
|
|
273
|
+
const rId = resolve(ctx, right);
|
|
274
|
+
if (lId === null && rId === null) {
|
|
275
|
+
return out;
|
|
276
|
+
}
|
|
277
|
+
const budget = { n: hubBound(ctx) * ctx.space.maxGroup };
|
|
278
|
+
// Left-side synonyms: containers of sibling+right. `right`'s seeds are
|
|
279
|
+
// FIXED across every sibling this loop tries.
|
|
280
|
+
if (lId !== null) {
|
|
281
|
+
const rightSeeds = junctionSeeds(ctx, right);
|
|
282
|
+
for (const sib of await haloSiblings(ctx, lId)) {
|
|
283
|
+
const sibBytes = read(ctx, sib.id, maxInterior + 1);
|
|
284
|
+
if (sibBytes.length === 0 || sibBytes.length > maxInterior) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
const containers = junctionContainersFrom(
|
|
288
|
+
ctx,
|
|
289
|
+
sibBytes,
|
|
290
|
+
right,
|
|
291
|
+
sibBytes.length + right.length + maxInterior,
|
|
292
|
+
junctionSeeds(ctx, sibBytes),
|
|
293
|
+
rightSeeds,
|
|
294
|
+
budget,
|
|
295
|
+
unordered,
|
|
296
|
+
);
|
|
297
|
+
for (const c of containers) {
|
|
298
|
+
out.push(c);
|
|
299
|
+
}
|
|
247
300
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
301
|
+
}
|
|
302
|
+
// Right-side synonyms: containers of left+sibling. `left`'s seeds are
|
|
303
|
+
// likewise fixed across this loop.
|
|
304
|
+
if (rId !== null) {
|
|
305
|
+
const leftSeeds = junctionSeeds(ctx, left);
|
|
306
|
+
for (const sib of await haloSiblings(ctx, rId)) {
|
|
307
|
+
const sibBytes = read(ctx, sib.id, maxInterior + 1);
|
|
308
|
+
if (sibBytes.length === 0 || sibBytes.length > maxInterior) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
const containers = junctionContainersFrom(
|
|
312
|
+
ctx,
|
|
313
|
+
left,
|
|
314
|
+
sibBytes,
|
|
315
|
+
left.length + sibBytes.length + maxInterior,
|
|
316
|
+
leftSeeds,
|
|
317
|
+
junctionSeeds(ctx, sibBytes),
|
|
318
|
+
budget,
|
|
319
|
+
unordered,
|
|
320
|
+
);
|
|
321
|
+
for (const c of containers) {
|
|
322
|
+
out.push(c);
|
|
323
|
+
}
|
|
260
324
|
}
|
|
261
|
-
|
|
325
|
+
}
|
|
326
|
+
return out;
|
|
262
327
|
}
|