@hviana/sema 0.1.2 → 0.1.4

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.
@@ -0,0 +1,31 @@
1
+ import { Permutation, Vec } from "./vec.js";
2
+ /** The one structure. A node's vector is the gist of its whole subtree; it also
3
+ * carries the structure the DAG store interns — its leaf bytes, or its kids. */
4
+ export interface Sema {
5
+ v: Vec;
6
+ leaf: Uint8Array | null;
7
+ kids: Sema[] | null;
8
+ }
9
+ export declare const sema: (v: Vec, leaf?: Uint8Array | null, kids?: Sema[] | null) => Sema;
10
+ /** Whether a node is a CHUNK — a leaf-parent whose children are ALL leaves,
11
+ * the perception tree's smallest grouped unit. The one predicate behind
12
+ * region collection, canonical segmentation seams, and sub-span indexing;
13
+ * named here beside the type so no consumer restates the shape inline. */
14
+ export declare const isChunk: (n: Sema) => n is Sema & {
15
+ kids: Sema[];
16
+ };
17
+ /** The medium: dimension, keyring, and noise source. */
18
+ export interface Space {
19
+ D: number;
20
+ seats: Permutation[];
21
+ rand: () => number;
22
+ maxGroup: number;
23
+ }
24
+ /** Bind one vector into a seat — the elementary half of fold. Used to index an
25
+ * episode from either side and to pour a partner into a form's halo. */
26
+ export declare const bindSeat: (space: Space, v: Vec, seat: number) => Vec;
27
+ /** The company signature of node `id` — the halo's pour unit (see above). */
28
+ export declare function companySignature(space: Space, id: number): Vec;
29
+ /** fold — combine ordered children into one gist.
30
+ * Each child is turned with its seat's own key, superposed, normalized. */
31
+ export declare function fold(space: Space, kids: Vec[]): Vec;
@@ -0,0 +1,63 @@
1
+ import { addInto, normalize, permute, permuteInto, randomUnit, rng, zeros, } from "./vec.js";
2
+ export const sema = (v, leaf = null, kids = null) => ({ v, leaf, kids });
3
+ /** Whether a node is a CHUNK — a leaf-parent whose children are ALL leaves,
4
+ * the perception tree's smallest grouped unit. The one predicate behind
5
+ * region collection, canonical segmentation seams, and sub-span indexing;
6
+ * named here beside the type so no consumer restates the shape inline. */
7
+ export const isChunk = (n) => n.kids !== null && n.kids.every((k) => k.kids === null);
8
+ // Reusable permute buffer for fold.
9
+ let _foldBuf = null;
10
+ /** Bind one vector into a seat — the elementary half of fold. Used to index an
11
+ * episode from either side and to pour a partner into a form's halo. */
12
+ export const bindSeat = (space, v, seat) => permute(v, space.seats[seat].fwd);
13
+ // ── Company signatures ──────────────────────────────────────────────────
14
+ //
15
+ // A halo is a superposition of EPISODE SIGNATURES: it answers "who does this
16
+ // form keep company with", and two forms share a concept when they keep the
17
+ // SAME company (the same partner nodes). Pouring the partner's raw GIST was
18
+ // an approximation of that: it worked while the hierarchical fold decorrelated
19
+ // unrelated gists quickly, but any byte-overlap between partners leaks CONTENT
20
+ // similarity into COMPANY similarity, silently shifting the halo null model
21
+ // that conceptThreshold's derivation (unrelated halos ⇒ cosine 0 ± 1/√D)
22
+ // depends on. A signature makes the semantics exact and fold-independent:
23
+ // a deterministic unit vector derived from the partner's IDENTITY, so two
24
+ // halos correlate exactly as much as their company overlaps — never because
25
+ // their partners merely contain similar bytes.
26
+ //
27
+ // Seeded by node id: ids are content-addressed mint order, stable for a given
28
+ // corpus (including checkpoint/resume, which re-derives identical ids), and
29
+ // halos are per-store training artifacts that are never compared across
30
+ // stores.
31
+ const _sigCache = new WeakMap();
32
+ const SIG_CACHE_MAX = 65_536;
33
+ /** The company signature of node `id` — the halo's pour unit (see above). */
34
+ export function companySignature(space, id) {
35
+ let cache = _sigCache.get(space);
36
+ if (!cache)
37
+ _sigCache.set(space, cache = new Map());
38
+ const hit = cache.get(id);
39
+ if (hit)
40
+ return hit;
41
+ const v = randomUnit(space.D, rng((id ^ 0x9e3779b9) >>> 0));
42
+ if (cache.size >= SIG_CACHE_MAX)
43
+ cache.clear(); // flat cap; regeneration is cheap
44
+ cache.set(id, v);
45
+ return v;
46
+ }
47
+ /** fold — combine ordered children into one gist.
48
+ * Each child is turned with its seat's own key, superposed, normalized. */
49
+ export function fold(space, kids) {
50
+ if (kids.length > space.seats.length) {
51
+ throw new Error(`fold: ${kids.length} children but the keyring has only ${space.seats.length} seats`);
52
+ }
53
+ const out = zeros(space.D);
54
+ if (!_foldBuf || _foldBuf.length !== space.D) {
55
+ _foldBuf = new Float32Array(space.D);
56
+ }
57
+ const buf = _foldBuf;
58
+ for (let i = 0; i < kids.length; i++) {
59
+ permuteInto(buf, kids[i], space.seats[i].fwd);
60
+ addInto(out, buf);
61
+ }
62
+ return normalize(out);
63
+ }
package/package.json CHANGED
@@ -1,10 +1,16 @@
1
1
  {
2
2
  "name": "@hviana/sema",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "An elementary, recursive, weight-free multimodal mind: one structure, two verbs, one memory. Zero runtime dependencies, pure web standards.",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
7
7
  "types": "dist/src/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/src/index.d.ts",
11
+ "default": "./dist/src/index.js"
12
+ }
13
+ },
8
14
  "scripts": {
9
15
  "build": "tsc",
10
16
  "demo": "tsc && node dist/example/demo.js",
package/src/sema.ts ADDED
@@ -0,0 +1,102 @@
1
+ import {
2
+ addInto,
3
+ normalize,
4
+ Permutation,
5
+ permute,
6
+ permuteInto,
7
+ randomUnit,
8
+ rng,
9
+ Vec,
10
+ zeros,
11
+ } from "./vec.js";
12
+
13
+ /** The one structure. A node's vector is the gist of its whole subtree; it also
14
+ * carries the structure the DAG store interns — its leaf bytes, or its kids. */
15
+ export interface Sema {
16
+ v: Vec;
17
+ leaf: Uint8Array | null;
18
+ kids: Sema[] | null;
19
+ }
20
+
21
+ export const sema = (
22
+ v: Vec,
23
+ leaf: Uint8Array | null = null,
24
+ kids: Sema[] | null = null,
25
+ ): Sema => ({ v, leaf, kids });
26
+
27
+ /** Whether a node is a CHUNK — a leaf-parent whose children are ALL leaves,
28
+ * the perception tree's smallest grouped unit. The one predicate behind
29
+ * region collection, canonical segmentation seams, and sub-span indexing;
30
+ * named here beside the type so no consumer restates the shape inline. */
31
+ export const isChunk = (n: Sema): n is Sema & { kids: Sema[] } =>
32
+ n.kids !== null && n.kids.every((k) => k.kids === null);
33
+
34
+ /** The medium: dimension, keyring, and noise source. */
35
+ export interface Space {
36
+ D: number;
37
+ seats: Permutation[];
38
+ rand: () => number;
39
+ maxGroup: number;
40
+ }
41
+
42
+ // Reusable permute buffer for fold.
43
+ let _foldBuf: Vec | null = null;
44
+
45
+ /** Bind one vector into a seat — the elementary half of fold. Used to index an
46
+ * episode from either side and to pour a partner into a form's halo. */
47
+ export const bindSeat = (space: Space, v: Vec, seat: number): Vec =>
48
+ permute(v, space.seats[seat].fwd);
49
+
50
+ // ── Company signatures ──────────────────────────────────────────────────
51
+ //
52
+ // A halo is a superposition of EPISODE SIGNATURES: it answers "who does this
53
+ // form keep company with", and two forms share a concept when they keep the
54
+ // SAME company (the same partner nodes). Pouring the partner's raw GIST was
55
+ // an approximation of that: it worked while the hierarchical fold decorrelated
56
+ // unrelated gists quickly, but any byte-overlap between partners leaks CONTENT
57
+ // similarity into COMPANY similarity, silently shifting the halo null model
58
+ // that conceptThreshold's derivation (unrelated halos ⇒ cosine 0 ± 1/√D)
59
+ // depends on. A signature makes the semantics exact and fold-independent:
60
+ // a deterministic unit vector derived from the partner's IDENTITY, so two
61
+ // halos correlate exactly as much as their company overlaps — never because
62
+ // their partners merely contain similar bytes.
63
+ //
64
+ // Seeded by node id: ids are content-addressed mint order, stable for a given
65
+ // corpus (including checkpoint/resume, which re-derives identical ids), and
66
+ // halos are per-store training artifacts that are never compared across
67
+ // stores.
68
+
69
+ const _sigCache = new WeakMap<Space, Map<number, Vec>>();
70
+ const SIG_CACHE_MAX = 65_536;
71
+
72
+ /** The company signature of node `id` — the halo's pour unit (see above). */
73
+ export function companySignature(space: Space, id: number): Vec {
74
+ let cache = _sigCache.get(space);
75
+ if (!cache) _sigCache.set(space, cache = new Map());
76
+ const hit = cache.get(id);
77
+ if (hit) return hit;
78
+ const v = randomUnit(space.D, rng((id ^ 0x9e3779b9) >>> 0));
79
+ if (cache.size >= SIG_CACHE_MAX) cache.clear(); // flat cap; regeneration is cheap
80
+ cache.set(id, v);
81
+ return v;
82
+ }
83
+
84
+ /** fold — combine ordered children into one gist.
85
+ * Each child is turned with its seat's own key, superposed, normalized. */
86
+ export function fold(space: Space, kids: Vec[]): Vec {
87
+ if (kids.length > space.seats.length) {
88
+ throw new Error(
89
+ `fold: ${kids.length} children but the keyring has only ${space.seats.length} seats`,
90
+ );
91
+ }
92
+ const out = zeros(space.D);
93
+ if (!_foldBuf || _foldBuf.length !== space.D) {
94
+ _foldBuf = new Float32Array(space.D);
95
+ }
96
+ const buf = _foldBuf;
97
+ for (let i = 0; i < kids.length; i++) {
98
+ permuteInto(buf, kids[i], space.seats[i].fwd);
99
+ addInto(out, buf);
100
+ }
101
+ return normalize(out);
102
+ }