@hviana/sema 0.5.8 → 0.5.9
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/AGENTS.md +23 -0
- package/DATASETS.md +159 -0
- package/README.md +12 -0
- package/dist/example/train_base.d.ts +73 -3
- package/dist/example/train_base.js +1000 -49
- package/dist/src/geometry.d.ts +20 -0
- package/dist/src/geometry.js +22 -0
- package/dist/src/mind/attention.d.ts +6 -0
- package/dist/src/mind/attention.js +44 -4
- package/dist/src/mind/learning.js +134 -50
- package/dist/src/mind/mechanisms/cast.js +45 -1
- package/dist/src/mind/mind.d.ts +6 -1
- package/dist/src/mind/mind.js +14 -2
- package/dist/src/mind/reasoning.js +59 -5
- package/dist/src/mind/recognition.js +29 -3
- package/dist/src/mind/traverse.d.ts +16 -0
- package/dist/src/mind/traverse.js +18 -0
- package/dist/src/store-sqlite.d.ts +4 -0
- package/dist/src/store-sqlite.js +47 -0
- package/dist/src/store.d.ts +7 -0
- package/example/train_base.ts +1193 -46
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/geometry.ts +23 -0
- package/src/mind/attention.ts +54 -1
- package/src/mind/learning.ts +137 -43
- package/src/mind/mechanisms/cast.ts +48 -1
- package/src/mind/mind.ts +12 -1
- package/src/mind/reasoning.ts +64 -5
- package/src/mind/recognition.ts +29 -3
- package/src/mind/traverse.ts +19 -0
- package/src/store-sqlite.ts +53 -0
- package/src/store.ts +28 -0
- package/test/29-counterfactual.test.mjs +43 -6
- package/test/77-company-saturation.test.mjs +302 -0
- package/test/78-atom-hub-recognition-cliff.test.mjs +135 -0
- package/test/84-composed-answer-honesty.test.mjs +136 -0
- package/test/85-answered-directly.test.mjs +126 -0
- package/test/86-cast-voices-committed.test.mjs +164 -0
- package/test/87-codominant-commitment.test.mjs +250 -0
|
@@ -407,6 +407,24 @@ export function atomReach(ctx, contextCount) {
|
|
|
407
407
|
export function atomIsHub(ctx, contextCount) {
|
|
408
408
|
return atomReach(ctx, contextCount) > boundFor(contextCount);
|
|
409
409
|
}
|
|
410
|
+
/** Cached "does this node bear a continuation edge?" — the CHEAP half of
|
|
411
|
+
* {@link leadsSomewhere}, exported for hot paths that must PRE-FILTER a
|
|
412
|
+
* candidate before paying for a fold and cannot afford the halo tier.
|
|
413
|
+
*
|
|
414
|
+
* `leadsSomewhere`'s second tier (`hasHalo`) is deliberately uncached — one
|
|
415
|
+
* indexed point probe per candidate, which is right where candidates are
|
|
416
|
+
* already few. On recognition's off-boundary chain pass they are not few:
|
|
417
|
+
* using the full predicate there took haloProbes from 922 to 9,144 on a
|
|
418
|
+
* nine-query battery over the trained store. The edge tier alone is memoised
|
|
419
|
+
* for the response, so it is ~free, and a node bearing an edge is exactly the
|
|
420
|
+
* "deposited whole, not an interned fragment" claim that pass needs.
|
|
421
|
+
*
|
|
422
|
+
* Strictly NARROWER than `leadsSomewhere` — a halo-only node reads false — so
|
|
423
|
+
* it is sound as a pre-filter before a consumer that applies the full
|
|
424
|
+
* predicate, and never as a replacement for it. */
|
|
425
|
+
export function bearsEdge(ctx, id) {
|
|
426
|
+
return cachedHasNext(ctx, id, getStructCache(ctx));
|
|
427
|
+
}
|
|
410
428
|
/** Whether a node LEADS SOMEWHERE — it bears a continuation edge or a halo.
|
|
411
429
|
* The admission predicate recognition filters sites with (HOW_IT_WORKS
|
|
412
430
|
* §15.3): a form that leads nowhere contributes nothing to any derivation.
|
|
@@ -46,6 +46,8 @@ export declare class SQliteStore extends AbstractStore implements Store {
|
|
|
46
46
|
private _insCanon;
|
|
47
47
|
private _selCanon;
|
|
48
48
|
private _cntCanon;
|
|
49
|
+
private _insSketch;
|
|
50
|
+
private _selSketch;
|
|
49
51
|
private _selContentFrom;
|
|
50
52
|
private _delMeta;
|
|
51
53
|
private _insSnapshot;
|
|
@@ -136,6 +138,8 @@ export declare class SQliteStore extends AbstractStore implements Store {
|
|
|
136
138
|
protected _dbDeleteMeta(key: string): void;
|
|
137
139
|
canonAdd(h: number, id: number): void;
|
|
138
140
|
canonFind(h: number): number[];
|
|
141
|
+
sketchGet(id: number): number[] | null;
|
|
142
|
+
sketchPut(id: number, ids: readonly number[]): void;
|
|
139
143
|
canonCount(): number;
|
|
140
144
|
eachContent(cb: (id: number, bytes: Uint8Array) => void, fromId?: number): void;
|
|
141
145
|
protected _dbSaveSnapshot(bytes: Uint8Array): void;
|
package/dist/src/store-sqlite.js
CHANGED
|
@@ -124,6 +124,20 @@ CREATE TABLE IF NOT EXISTS canon (
|
|
|
124
124
|
id INTEGER NOT NULL,
|
|
125
125
|
PRIMARY KEY (h, id)
|
|
126
126
|
) WITHOUT ROWID;
|
|
127
|
+
-- CONSTITUENT SKETCH (Store.sketchGet/sketchPut): the bottom-k minimal
|
|
128
|
+
-- constituents of a node's subtree, k = √D, chosen by identity hash. The blob is
|
|
129
|
+
-- a packed int32 little-endian run, already in hash order; an EMPTY blob is a
|
|
130
|
+
-- real answer (a minimal unit has no constituents) and a MISSING ROW means
|
|
131
|
+
-- "not yet computed" — the two must stay distinguishable, which is why absence
|
|
132
|
+
-- is a missing row rather than an empty blob sentinel. (node:sqlite binds a
|
|
133
|
+
-- zero-length Uint8Array as NULL, so the column is nullable and a NULL blob
|
|
134
|
+
-- reads back as the empty sketch — the ROW is what records "computed".)
|
|
135
|
+
-- Measured on the trained
|
|
136
|
+
-- store: 80.8% of nodes sketch EMPTY, mean 1.14 ids, ~72 MB over 15.7M nodes.
|
|
137
|
+
CREATE TABLE IF NOT EXISTS sketch (
|
|
138
|
+
id INTEGER PRIMARY KEY,
|
|
139
|
+
ids BLOB
|
|
140
|
+
);
|
|
127
141
|
CREATE TABLE IF NOT EXISTS snapshot (
|
|
128
142
|
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
129
143
|
data BLOB NOT NULL
|
|
@@ -227,6 +241,8 @@ export class SQliteStore extends AbstractStore {
|
|
|
227
241
|
_insCanon = null;
|
|
228
242
|
_selCanon = null;
|
|
229
243
|
_cntCanon = null;
|
|
244
|
+
_insSketch = null;
|
|
245
|
+
_selSketch = null;
|
|
230
246
|
_selContentFrom = null;
|
|
231
247
|
_delMeta = null;
|
|
232
248
|
_insSnapshot = null;
|
|
@@ -829,6 +845,37 @@ export class SQliteStore extends AbstractStore {
|
|
|
829
845
|
}
|
|
830
846
|
return this._selCanon.all(h).map((r) => r.id);
|
|
831
847
|
}
|
|
848
|
+
// -- Constituent sketch (Store optional capability) --
|
|
849
|
+
sketchGet(id) {
|
|
850
|
+
if (!this._selSketch) {
|
|
851
|
+
this._selSketch = this.sqlite.prepare("SELECT ids FROM sketch WHERE id = ?");
|
|
852
|
+
}
|
|
853
|
+
const row = this._selSketch.get(id);
|
|
854
|
+
if (row === undefined)
|
|
855
|
+
return null; // never computed — NOT the same as []
|
|
856
|
+
const b = row.ids;
|
|
857
|
+
if (b === null || b.byteLength === 0)
|
|
858
|
+
return []; // computed, no constituents
|
|
859
|
+
const out = [];
|
|
860
|
+
const dv = new DataView(b.buffer, b.byteOffset, b.byteLength);
|
|
861
|
+
for (let i = 0; i + 4 <= b.byteLength; i += 4) {
|
|
862
|
+
out.push(dv.getInt32(i, true));
|
|
863
|
+
}
|
|
864
|
+
return out;
|
|
865
|
+
}
|
|
866
|
+
sketchPut(id, ids) {
|
|
867
|
+
if (!this._insSketch) {
|
|
868
|
+
this._insSketch = this.sqlite.prepare("INSERT OR REPLACE INTO sketch (id, ids) VALUES (?, ?)");
|
|
869
|
+
}
|
|
870
|
+
const b = new Uint8Array(ids.length * 4);
|
|
871
|
+
const dv = new DataView(b.buffer);
|
|
872
|
+
for (let i = 0; i < ids.length; i++)
|
|
873
|
+
dv.setInt32(i * 4, ids[i], true);
|
|
874
|
+
// Join the deferred write transaction (committed by flush/commit), like
|
|
875
|
+
// canonAdd — a training run writes these in bulk.
|
|
876
|
+
this._dbBeginTx();
|
|
877
|
+
this._insSketch.run(id, b);
|
|
878
|
+
}
|
|
832
879
|
canonCount() {
|
|
833
880
|
if (!this._cntCanon) {
|
|
834
881
|
this._cntCanon = this.sqlite.prepare("SELECT count(*) AS c FROM canon");
|
package/dist/src/store.d.ts
CHANGED
|
@@ -324,6 +324,13 @@ export interface Store {
|
|
|
324
324
|
* restricts the scan to ids ≥ fromId, so an index refresh after further
|
|
325
325
|
* training only visits the new rows. */
|
|
326
326
|
eachContent?(cb: (id: NodeId, bytes: Uint8Array) => void, fromId?: NodeId): void;
|
|
327
|
+
/** The stored sketch of `id`, or null when it has never been computed.
|
|
328
|
+
* An empty array is a REAL answer (a minimal unit has no constituents) and
|
|
329
|
+
* must be distinguished from null. */
|
|
330
|
+
sketchGet?(id: NodeId): NodeId[] | null;
|
|
331
|
+
/** Record `ids` as the sketch of `id`. Idempotent; ids are already sorted
|
|
332
|
+
* by the caller's identity hash. */
|
|
333
|
+
sketchPut?(id: NodeId, ids: readonly NodeId[]): void;
|
|
327
334
|
size(): Promise<number>;
|
|
328
335
|
saveSnapshot(bytes: Uint8Array): Promise<void>;
|
|
329
336
|
loadSnapshot(): Promise<Uint8Array | null>;
|