@hviana/sema 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/geometry.d.ts +28 -0
- package/dist/src/geometry.js +35 -0
- package/dist/src/mind/articulation.js +1 -1
- package/dist/src/mind/attention.d.ts +4 -0
- package/dist/src/mind/attention.js +65 -12
- package/dist/src/mind/graph-search.d.ts +16 -1
- package/dist/src/mind/graph-search.js +34 -5
- package/dist/src/mind/learning.d.ts +1 -1
- package/dist/src/mind/learning.js +20 -5
- package/dist/src/mind/mechanisms/alu.js +8 -1
- package/dist/src/mind/mechanisms/cast.js +35 -11
- package/dist/src/mind/mechanisms/cover.js +40 -1
- package/dist/src/mind/mechanisms/extraction.js +75 -30
- package/dist/src/mind/mechanisms/recall.js +26 -2
- package/dist/src/mind/mind.d.ts +3 -2
- package/dist/src/mind/mind.js +28 -54
- package/dist/src/mind/pipeline.js +34 -2
- package/dist/src/mind/primitives.d.ts +16 -9
- package/dist/src/mind/primitives.js +58 -22
- package/dist/src/mind/reasoning.d.ts +9 -1
- package/dist/src/mind/reasoning.js +26 -4
- package/dist/src/mind/recognition.js +30 -6
- package/dist/src/mind/traverse.js +15 -0
- package/dist/src/mind/types.d.ts +58 -10
- package/dist/src/mind/types.js +15 -0
- package/package.json +1 -1
- package/src/geometry.ts +61 -1
- package/src/mind/articulation.ts +1 -0
- package/src/mind/attention.ts +80 -12
- package/src/mind/graph-search.ts +59 -2
- package/src/mind/learning.ts +20 -3
- package/src/mind/mechanisms/alu.ts +8 -1
- package/src/mind/mechanisms/cast.ts +46 -8
- package/src/mind/mechanisms/cover.ts +46 -0
- package/src/mind/mechanisms/extraction.ts +101 -40
- package/src/mind/mechanisms/recall.ts +30 -2
- package/src/mind/mind.ts +38 -61
- package/src/mind/pipeline.ts +37 -2
- package/src/mind/primitives.ts +71 -29
- package/src/mind/reasoning.ts +26 -3
- package/src/mind/recognition.ts +28 -5
- package/src/mind/traverse.ts +18 -0
- package/src/mind/types.ts +73 -10
- package/test/35-attention-confidence.test.mjs +139 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// 35-attention-confidence.test.mjs — SCALE-INVARIANT CONFIDENCE for a point
|
|
2
|
+
// of attention (Attention.breadth).
|
|
3
|
+
//
|
|
4
|
+
// commitVotes always admits the DOMINANT root regardless of its IDF-weighted
|
|
5
|
+
// vote (attention.ts: "roots.length === 0 || ..." — the first root is never
|
|
6
|
+
// floor-gated). That is correct for the common case ("give me your best
|
|
7
|
+
// guess"), but it means a query's SOLE root can be either:
|
|
8
|
+
//
|
|
9
|
+
// (a) genuine consensus — most of the query's own regions independently
|
|
10
|
+
// corroborate it (a real fact, or a real cross-region binding), or
|
|
11
|
+
// (b) a coincidental echo — ONE region's resonance happened to land
|
|
12
|
+
// somewhere, with the rest of the query silent on it.
|
|
13
|
+
//
|
|
14
|
+
// The raw IDF vote cannot tell these apart: it is an ABSOLUTE quantity that
|
|
15
|
+
// scales with ln(corpus size), so the same vote means "strong" on a small
|
|
16
|
+
// store and "weak" on a large one (see the session's earlier finding: a
|
|
17
|
+
// genuine root on a 325K-context store scored BELOW its own consensus floor,
|
|
18
|
+
// while a spurious echo on a 15-fact store scored comfortably above its own —
|
|
19
|
+
// much smaller — floor). A SCALE-INVARIANT measure is needed instead: what
|
|
20
|
+
// FRACTION of the query's own regions this root's evidence accounts for —
|
|
21
|
+
// the "N of M sub-regions voted" the rationale already reports, but read
|
|
22
|
+
// PER-ANCHOR instead of globally, and tested against the same half-dominance
|
|
23
|
+
// convention (`dominates`, part*2 > whole) the rest of the codebase already
|
|
24
|
+
// uses for every other "is this real signal or noise" decision.
|
|
25
|
+
|
|
26
|
+
import { test } from "node:test";
|
|
27
|
+
import assert from "node:assert/strict";
|
|
28
|
+
import { Mind } from "../dist/src/index.js";
|
|
29
|
+
import { SQliteStore } from "../dist/src/store-sqlite.js";
|
|
30
|
+
|
|
31
|
+
const enc = (s) => new TextEncoder().encode(s);
|
|
32
|
+
const mk = (seed) =>
|
|
33
|
+
new Mind({ seed, store: new SQliteStore({ path: ":memory:" }) });
|
|
34
|
+
|
|
35
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
36
|
+
// GENUINE CONSENSUS — a real cross-region binding (test/34's own corpus).
|
|
37
|
+
// Most of the query's regions agree on the joint context; breadth must
|
|
38
|
+
// DOMINATE (> half of the query's own regions corroborate it).
|
|
39
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
40
|
+
|
|
41
|
+
const BINDING_CORPUS = [
|
|
42
|
+
["red", "is a color"],
|
|
43
|
+
["blue", "is a color"],
|
|
44
|
+
["circle", "is a shape"],
|
|
45
|
+
["square", "is a shape"],
|
|
46
|
+
["red circle", "answer alpha"],
|
|
47
|
+
["red square", "answer beta"],
|
|
48
|
+
["blue circle", "answer gamma"],
|
|
49
|
+
["blue square", "answer delta"],
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
test("breadth: a genuine cross-region binding dominates the query's regions", async () => {
|
|
53
|
+
const m = mk(1);
|
|
54
|
+
await m.ingest(BINDING_CORPUS);
|
|
55
|
+
const roots = await m.climbAttention(enc("red then circle"), 24);
|
|
56
|
+
assert.equal(roots.length, 1, "expected exactly one committed root");
|
|
57
|
+
assert.ok(
|
|
58
|
+
typeof roots[0].breadth === "number",
|
|
59
|
+
"Attention must carry a breadth field",
|
|
60
|
+
);
|
|
61
|
+
assert.ok(
|
|
62
|
+
roots[0].breadth > 0.5,
|
|
63
|
+
`genuine binding must dominate (> half the query's own regions), got breadth=${
|
|
64
|
+
roots[0].breadth
|
|
65
|
+
}`,
|
|
66
|
+
);
|
|
67
|
+
await m.store.close();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
71
|
+
// SPURIOUS ECHO — a short arithmetic query whose consensus climb lands on an
|
|
72
|
+
// UNRELATED fact by coincidental byte-pattern resonance (observed directly
|
|
73
|
+
// this session: "2+2 equals what?" climbs to "1+1", not "2+2"). Only a
|
|
74
|
+
// minority of the query's regions support it; breadth must NOT dominate.
|
|
75
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
76
|
+
|
|
77
|
+
const ARITH_CORPUS = [
|
|
78
|
+
["1+2", "3"],
|
|
79
|
+
["2+2", "4"],
|
|
80
|
+
["2+3", "5"],
|
|
81
|
+
["3+3", "6"],
|
|
82
|
+
["3+5", "8"],
|
|
83
|
+
["4+3", "7"],
|
|
84
|
+
["2+5", "7"],
|
|
85
|
+
["1+5", "6"],
|
|
86
|
+
["6+1", "7"],
|
|
87
|
+
["4+1", "5"],
|
|
88
|
+
["3+4", "7"],
|
|
89
|
+
["5+2", "7"],
|
|
90
|
+
["1+1", "2"],
|
|
91
|
+
["5+3", "8"],
|
|
92
|
+
["7+1", "8"],
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
test("breadth: a coincidental single-region echo does not dominate", async () => {
|
|
96
|
+
const m = mk(1);
|
|
97
|
+
await m.ingest(ARITH_CORPUS);
|
|
98
|
+
const roots = await m.climbAttention(enc("2+2 equals what?"), 24);
|
|
99
|
+
assert.equal(roots.length, 1, "expected exactly one committed root");
|
|
100
|
+
assert.ok(
|
|
101
|
+
typeof roots[0].breadth === "number",
|
|
102
|
+
"Attention must carry a breadth field",
|
|
103
|
+
);
|
|
104
|
+
assert.ok(
|
|
105
|
+
roots[0].breadth <= 0.5,
|
|
106
|
+
`a coincidental echo must NOT dominate the query's own regions, got breadth=${
|
|
107
|
+
roots[0].breadth
|
|
108
|
+
}`,
|
|
109
|
+
);
|
|
110
|
+
await m.store.close();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
114
|
+
// SCALE INVARIANCE — the whole point: the SAME breadth bar must separate
|
|
115
|
+
// signal from noise whether the corpus has 15 facts or many more, unlike the
|
|
116
|
+
// raw IDF vote (which is an absolute, ln(N)-scaled quantity — see the header
|
|
117
|
+
// comment). Doubling the corpus (more unrelated arithmetic facts) must not
|
|
118
|
+
// flip either verdict merely by changing N.
|
|
119
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
120
|
+
|
|
121
|
+
test("breadth: the same bar holds as the corpus grows (scale invariance)", async () => {
|
|
122
|
+
const bigArith = [...ARITH_CORPUS];
|
|
123
|
+
for (let a = 1; a <= 9; a++) {
|
|
124
|
+
for (let b = 1; b <= 9; b++) {
|
|
125
|
+
bigArith.push([`${a}x${b}`, String(a * b)]);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const m = mk(1);
|
|
129
|
+
await m.ingest(bigArith);
|
|
130
|
+
const roots = await m.climbAttention(enc("2+2 equals what?"), 24);
|
|
131
|
+
assert.equal(roots.length, 1, "expected exactly one committed root");
|
|
132
|
+
assert.ok(
|
|
133
|
+
roots[0].breadth <= 0.5,
|
|
134
|
+
`a coincidental echo must still not dominate on a larger corpus, got breadth=${
|
|
135
|
+
roots[0].breadth
|
|
136
|
+
}`,
|
|
137
|
+
);
|
|
138
|
+
await m.store.close();
|
|
139
|
+
});
|