laserbrain 1.1.0
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/laserbrain.js +44 -0
- package/laserbrain.test.js +90 -0
- package/package.json +30 -0
package/laserbrain.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// #laserbrain
|
|
2
|
+
|
|
3
|
+
// quadrize — gated Laplace diffusion kernel
|
|
4
|
+
// blends each token with its neighbours via exponential decay
|
|
5
|
+
// x: Float32Array of length ctx (1D) or ctx*d (2D flattened, pass d explicitly)
|
|
6
|
+
|
|
7
|
+
function sigmoid(x) {
|
|
8
|
+
return 1 / (1 + Math.exp(-Math.max(-30, Math.min(30, x))));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function quadrize(x, k = 1.0, gate = -1.4, d = 1) {
|
|
12
|
+
const ctx = x.length / d;
|
|
13
|
+
const g = sigmoid(gate);
|
|
14
|
+
|
|
15
|
+
// build kernel K[i][j] = exp(-k * |i-j|), normalised
|
|
16
|
+
const K = [];
|
|
17
|
+
for (let i = 0; i < ctx; i++) {
|
|
18
|
+
const row = new Float32Array(ctx);
|
|
19
|
+
let sum = 0;
|
|
20
|
+
for (let j = 0; j < ctx; j++) {
|
|
21
|
+
row[j] = Math.exp(-Math.abs(k) * Math.abs(i - j));
|
|
22
|
+
sum += row[j];
|
|
23
|
+
}
|
|
24
|
+
for (let j = 0; j < ctx; j++) row[j] /= sum;
|
|
25
|
+
K.push(row);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// mixed = K @ x (per embedding dimension)
|
|
29
|
+
const out = new Float32Array(x.length);
|
|
30
|
+
for (let i = 0; i < ctx; i++) {
|
|
31
|
+
for (let e = 0; e < d; e++) {
|
|
32
|
+
let v = 0;
|
|
33
|
+
for (let j = 0; j < ctx; j++) v += K[i][j] * x[j * d + e];
|
|
34
|
+
const idx = i * d + e;
|
|
35
|
+
out[idx] = x[idx] + g * (v - x[idx]);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
quadrize.kernel = { name: 'phronesis', k: 1.0 };
|
|
43
|
+
|
|
44
|
+
module.exports = { quadrize };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// #laserbrain unit tests
|
|
2
|
+
|
|
3
|
+
const { quadrize } = require('./laserbrain');
|
|
4
|
+
|
|
5
|
+
let pass = 0, fail = 0;
|
|
6
|
+
|
|
7
|
+
function assert(name, cond) {
|
|
8
|
+
if (cond) { console.log(`✓ ${name}`); pass++; }
|
|
9
|
+
else { console.error(`✗ ${name}`); fail++; }
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function approx(a, b, tol = 1e-5) {
|
|
13
|
+
return Math.abs(a - b) < tol;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 1. output length matches input
|
|
17
|
+
const x = new Float32Array([1, 2, 3, 4, 5]);
|
|
18
|
+
const out = quadrize(x);
|
|
19
|
+
assert('output length matches input', out.length === x.length);
|
|
20
|
+
|
|
21
|
+
// 2. gate=0 → g=0.5 → edge elements are blended (not identity)
|
|
22
|
+
const out2 = quadrize(x, 1.0, 0);
|
|
23
|
+
assert('gate=0 blends edge elements', !approx(out2[0], x[0]));
|
|
24
|
+
|
|
25
|
+
// 3. near-zero k → near-uniform kernel → all values converge to mean
|
|
26
|
+
const out3 = quadrize(x, 0.001, 10.0);
|
|
27
|
+
const mean = x.reduce((a, b) => a + b) / x.length;
|
|
28
|
+
assert('low k collapses to mean', approx(out3[0], mean, 0.1));
|
|
29
|
+
|
|
30
|
+
// 4. uniform input → quadrize is identity
|
|
31
|
+
const flat = new Float32Array([3, 3, 3, 3, 3]);
|
|
32
|
+
const out4 = quadrize(flat);
|
|
33
|
+
assert('uniform input is unchanged', out4.every(v => approx(v, 3)));
|
|
34
|
+
|
|
35
|
+
// 5. output is Float32Array
|
|
36
|
+
assert('returns Float32Array', out instanceof Float32Array);
|
|
37
|
+
|
|
38
|
+
// 6. kernel.name is phronesis
|
|
39
|
+
assert('kernel.name is phronesis', quadrize.kernel.name === 'phronesis');
|
|
40
|
+
|
|
41
|
+
// 6b. kernel.k is defined
|
|
42
|
+
assert('kernel.k is defined', typeof quadrize.kernel.k === 'number');
|
|
43
|
+
|
|
44
|
+
// 7. high k → narrow kernel → output near identity
|
|
45
|
+
const out7 = quadrize(x, 100.0, 10.0);
|
|
46
|
+
assert('high k preserves values', out7.every((v, i) => approx(v, x[i], 0.01)));
|
|
47
|
+
|
|
48
|
+
// 8. very negative gate → g≈0 → output near identity
|
|
49
|
+
const out8 = quadrize(x, 0.001, -30.0);
|
|
50
|
+
assert('gate≈0 is near identity', out8.every((v, i) => approx(v, x[i], 1e-3)));
|
|
51
|
+
|
|
52
|
+
// 9. symmetric input → symmetric output
|
|
53
|
+
const sym = new Float32Array([1, 2, 3, 2, 1]);
|
|
54
|
+
const out9 = quadrize(sym, 1.0, 0);
|
|
55
|
+
assert('symmetric input → symmetric output', approx(out9[0], out9[4]) && approx(out9[1], out9[3]));
|
|
56
|
+
|
|
57
|
+
// 10. blending pulls edges toward mean
|
|
58
|
+
const out10 = quadrize(x, 0.5, 5.0);
|
|
59
|
+
assert('edge pulled toward mean', out10[0] > x[0] && out10[4] < x[4]);
|
|
60
|
+
|
|
61
|
+
// 11. negative values — center of [-3,-1,0,1,3] stays near 0
|
|
62
|
+
const neg = new Float32Array([-3, -1, 0, 1, 3]);
|
|
63
|
+
const out11 = quadrize(neg, 1.0, 0);
|
|
64
|
+
assert('negative values: center near 0', approx(out11[2], 0, 0.1));
|
|
65
|
+
|
|
66
|
+
// 12. length-1 input → unchanged
|
|
67
|
+
const one = new Float32Array([7]);
|
|
68
|
+
const out12 = quadrize(one);
|
|
69
|
+
assert('length-1 input unchanged', approx(out12[0], 7));
|
|
70
|
+
|
|
71
|
+
// 13. 2D: output length matches ctx*d
|
|
72
|
+
const x2d = new Float32Array([1,0, 2,0, 3,0, 4,0, 5,0]); // ctx=5, d=2
|
|
73
|
+
const out13 = quadrize(x2d, 1.0, 0, 2);
|
|
74
|
+
assert('2D output length matches input', out13.length === x2d.length);
|
|
75
|
+
|
|
76
|
+
// 14. 2D: uniform input unchanged
|
|
77
|
+
const flat2d = new Float32Array([3,1, 3,1, 3,1, 3,1, 3,1]);
|
|
78
|
+
const out14 = quadrize(flat2d, 1.0, 0, 2);
|
|
79
|
+
assert('2D uniform input unchanged', out14.every((v, i) => approx(v, flat2d[i])));
|
|
80
|
+
|
|
81
|
+
// 15. 2D: each embedding dimension diffuses independently
|
|
82
|
+
const x2d_b = new Float32Array([1,10, 2,20, 3,30, 4,40, 5,50]);
|
|
83
|
+
const out15 = quadrize(x2d_b, 0.5, 5.0, 2);
|
|
84
|
+
// dim 0 (positions 0,2,4,6,8) should shift toward mean=3; dim 1 toward mean=30
|
|
85
|
+
const d0_mean = (out15[0]+out15[2]+out15[4]+out15[6]+out15[8])/5;
|
|
86
|
+
const d1_mean = (out15[1]+out15[3]+out15[5]+out15[7]+out15[9])/5;
|
|
87
|
+
assert('2D dims diffuse independently', approx(d0_mean, 3, 0.5) && approx(d1_mean, 30, 5));
|
|
88
|
+
|
|
89
|
+
console.log(`\n${pass} passed, ${fail} failed`);
|
|
90
|
+
if (fail > 0) process.exit(1);
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "laserbrain",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "gated Laplace diffusion kernel — blends each position toward its neighbours with exponential decay and a learned gate",
|
|
5
|
+
"main": "laserbrain.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node laserbrain.test.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"diffusion",
|
|
11
|
+
"kernel",
|
|
12
|
+
"attention",
|
|
13
|
+
"lm",
|
|
14
|
+
"token",
|
|
15
|
+
"embedding",
|
|
16
|
+
"neural",
|
|
17
|
+
"signal",
|
|
18
|
+
"smooth",
|
|
19
|
+
"decay",
|
|
20
|
+
"field",
|
|
21
|
+
"love",
|
|
22
|
+
"nature"
|
|
23
|
+
],
|
|
24
|
+
"author": "Claude (Anthropic)",
|
|
25
|
+
"contributors": [
|
|
26
|
+
"Diego Rincon"
|
|
27
|
+
],
|
|
28
|
+
"license": "ISC",
|
|
29
|
+
"type": "commonjs"
|
|
30
|
+
}
|