bireactive 0.2.4 → 0.3.1
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/animation/anim.js +4 -0
- package/dist/automerge/doc-cell.d.ts +20 -0
- package/dist/automerge/doc-cell.js +80 -0
- package/dist/automerge/index.d.ts +3 -0
- package/dist/automerge/index.js +12 -0
- package/dist/automerge/reconcile.d.ts +5 -0
- package/dist/automerge/reconcile.js +63 -0
- package/dist/coll.d.ts +7 -7
- package/dist/core/_counts.d.ts +48 -0
- package/dist/core/_counts.js +58 -0
- package/dist/core/cell.d.ts +182 -123
- package/dist/core/cell.js +1140 -721
- package/dist/core/debug.d.ts +25 -0
- package/dist/core/debug.js +121 -0
- package/dist/core/index.d.ts +9 -14
- package/dist/core/index.js +9 -14
- package/dist/core/lenses/aggregates.d.ts +1 -1
- package/dist/core/lenses/aggregates.js +4 -3
- package/dist/core/lenses/closed-form-policies.js +14 -9
- package/dist/core/lenses/decompositions.js +3 -3
- package/dist/core/lenses/domain-aggregates.js +5 -5
- package/dist/core/lenses/geometry.d.ts +1 -1
- package/dist/core/lenses/geometry.js +6 -7
- package/dist/core/lenses/index.d.ts +1 -0
- package/dist/core/lenses/index.js +1 -0
- package/dist/core/lenses/memory.d.ts +2 -2
- package/dist/core/lenses/memory.js +3 -3
- package/dist/core/lenses/snap.d.ts +18 -0
- package/dist/core/lenses/snap.js +145 -0
- package/dist/core/lenses/typed-factor.js +4 -3
- package/dist/core/optic.d.ts +13 -0
- package/dist/core/optic.js +44 -0
- package/dist/core/optics.d.ts +10 -0
- package/dist/core/optics.js +30 -0
- package/dist/core/store.d.ts +10 -0
- package/dist/core/store.js +85 -0
- package/dist/core/traits.d.ts +1 -0
- package/dist/core/values/audio.js +4 -5
- package/dist/core/values/box.js +7 -7
- package/dist/core/values/canvas.js +15 -18
- package/dist/core/values/color.js +5 -5
- package/dist/core/values/field.d.ts +70 -0
- package/dist/core/values/field.js +230 -0
- package/dist/core/values/gpu.d.ts +4 -2
- package/dist/core/values/gpu.js +11 -4
- package/dist/core/values/matrix.js +7 -7
- package/dist/core/values/num.d.ts +1 -1
- package/dist/core/values/num.js +1 -1
- package/dist/core/values/pose.js +4 -4
- package/dist/core/values/range.js +6 -6
- package/dist/core/values/str.js +8 -8
- package/dist/core/values/template.d.ts +1 -1
- package/dist/core/values/template.js +2 -1
- package/dist/core/values/transform.js +7 -7
- package/dist/core/values/tri.js +3 -3
- package/dist/core/values/vec.js +8 -12
- package/dist/ext/timeline.js +2 -2
- package/dist/formats/cst.d.ts +127 -0
- package/dist/formats/cst.js +280 -0
- package/dist/formats/edn.d.ts +2 -0
- package/dist/formats/edn.js +301 -0
- package/dist/formats/index.d.ts +6 -0
- package/dist/formats/index.js +8 -0
- package/dist/formats/json.d.ts +2 -0
- package/dist/formats/json.js +332 -0
- package/dist/formats/lens.d.ts +8 -0
- package/dist/formats/lens.js +51 -0
- package/dist/formats/toml.d.ts +2 -0
- package/dist/formats/toml.js +526 -0
- package/dist/formats/yaml.d.ts +2 -0
- package/dist/formats/yaml.js +661 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/jsx-dev-runtime.d.ts +2 -0
- package/dist/jsx-dev-runtime.js +5 -0
- package/dist/jsx-runtime.d.ts +54 -0
- package/dist/jsx-runtime.js +219 -0
- package/dist/learn/data.d.ts +49 -0
- package/dist/learn/data.js +181 -0
- package/dist/learn/index.d.ts +3 -0
- package/dist/learn/index.js +6 -0
- package/dist/learn/lens-net.d.ts +63 -0
- package/dist/learn/lens-net.js +219 -0
- package/dist/learn/mlp.d.ts +77 -0
- package/dist/learn/mlp.js +292 -0
- package/dist/propagators/csp.d.ts +13 -0
- package/dist/propagators/csp.js +52 -0
- package/dist/propagators/flex.d.ts +31 -0
- package/dist/propagators/flex.js +189 -0
- package/dist/propagators/graph.d.ts +73 -0
- package/dist/propagators/graph.js +543 -0
- package/dist/propagators/index.d.ts +8 -6
- package/dist/propagators/index.js +15 -6
- package/dist/propagators/lattice.d.ts +45 -0
- package/dist/propagators/lattice.js +113 -0
- package/dist/propagators/layout.d.ts +1 -27
- package/dist/propagators/layout.js +6 -175
- package/dist/propagators/numeric.d.ts +17 -0
- package/dist/propagators/numeric.js +93 -0
- package/dist/propagators/solver.d.ts +51 -0
- package/dist/propagators/solver.js +175 -0
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/lens.d.ts +121 -0
- package/dist/schema/lens.js +429 -0
- package/dist/shapes/annular-sector.js +4 -4
- package/dist/shapes/button.js +1 -1
- package/dist/shapes/circle.js +1 -1
- package/dist/shapes/drag-behaviors.d.ts +56 -0
- package/dist/shapes/drag-behaviors.js +102 -0
- package/dist/shapes/drag-spec.d.ts +52 -0
- package/dist/shapes/drag-spec.js +112 -0
- package/dist/shapes/handle.js +2 -2
- package/dist/shapes/index.d.ts +3 -1
- package/dist/shapes/index.js +3 -1
- package/dist/shapes/interaction.d.ts +2 -3
- package/dist/shapes/interaction.js +77 -56
- package/dist/shapes/label.js +7 -1
- package/dist/shapes/layout.d.ts +47 -1
- package/dist/shapes/layout.js +60 -2
- package/dist/shapes/rect.js +7 -7
- package/dist/shapes/shape.js +8 -8
- package/dist/web/diagram.js +2 -2
- package/package.json +24 -2
- package/dist/propagators/network.d.ts +0 -52
- package/dist/propagators/network.js +0 -185
- package/dist/propagators/propagator.d.ts +0 -12
- package/dist/propagators/propagator.js +0 -16
- package/dist/propagators/range.d.ts +0 -45
- package/dist/propagators/range.js +0 -147
- package/dist/propagators/relations.d.ts +0 -60
- package/dist/propagators/relations.js +0 -343
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Cell } from "./cell.js";
|
|
2
|
+
type SomeCell = Cell<any>;
|
|
3
|
+
/** Short, stable display name: the cell's `name`, else `Ctor#n`. */
|
|
4
|
+
export declare function label(c: SomeCell): string;
|
|
5
|
+
/** `source` (no getter), `lens` (writable derived), or `computed` (read-only derived). */
|
|
6
|
+
export declare function kind(c: SomeCell): "source" | "lens" | "computed";
|
|
7
|
+
/** Upstream cells: eager lens parents unioned with dynamic forward deps. */
|
|
8
|
+
export declare function upstream(c: SomeCell): Cell<unknown>[];
|
|
9
|
+
/** One-line summary: `name = value [kind]` plus upstream labels, if any. */
|
|
10
|
+
export declare function explain(c: SomeCell): string;
|
|
11
|
+
export interface DumpOpts {
|
|
12
|
+
/** Max upstream depth to descend. Default `Infinity`. */
|
|
13
|
+
depth?: number;
|
|
14
|
+
/** Include `= value` in each line. Default `true`. */
|
|
15
|
+
values?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Render the upstream graph of `root` as an indented tree (cycle-safe). */
|
|
18
|
+
export declare function dumpGraph(root: SomeCell, opts?: DumpOpts): string;
|
|
19
|
+
/** Run `fn` and collect the source cells written during it (back-writes included,
|
|
20
|
+
* since a view write commits through its sources' `_writeSource`). */
|
|
21
|
+
export declare function traceWrites<T>(fn: () => T): {
|
|
22
|
+
result: T;
|
|
23
|
+
writes: Cell<unknown>[];
|
|
24
|
+
};
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// debug.ts — read-only inspection of the cell graph (dev-time, no hot-path cost).
|
|
2
|
+
//
|
|
3
|
+
// Three small tools: `explain` (one line about a cell), `dumpGraph` (the upstream
|
|
4
|
+
// dependency tree), and `traceWrites` (which sources a block of work actually
|
|
5
|
+
// wrote). All walk the same edges the engine maintains — lens parents
|
|
6
|
+
// (`parentEdges`, eager) unioned with dynamic forward deps (`deps`, post-read) —
|
|
7
|
+
// and label cells by their optional `name` (falling back to `Ctor#n`). Nothing
|
|
8
|
+
// here mutates graph state; reads go through `peek` so they don't track.
|
|
9
|
+
import { Cell, isLens, isReadonly, setCellWriteHook } from "./cell.js";
|
|
10
|
+
const edges = (c) => c;
|
|
11
|
+
const erase = (c) => c;
|
|
12
|
+
const ids = new WeakMap();
|
|
13
|
+
let nextId = 1;
|
|
14
|
+
function idOf(c) {
|
|
15
|
+
let i = ids.get(c);
|
|
16
|
+
if (i === undefined) {
|
|
17
|
+
i = nextId++;
|
|
18
|
+
ids.set(c, i);
|
|
19
|
+
}
|
|
20
|
+
return i;
|
|
21
|
+
}
|
|
22
|
+
/** Short, stable display name: the cell's `name`, else `Ctor#n`. */
|
|
23
|
+
export function label(c) {
|
|
24
|
+
return c.name ?? `${c.constructor.name}#${idOf(erase(c))}`;
|
|
25
|
+
}
|
|
26
|
+
/** `source` (no getter), `lens` (writable derived), or `computed` (read-only derived). */
|
|
27
|
+
export function kind(c) {
|
|
28
|
+
return isLens(c) ? "lens" : isReadonly(c) ? "computed" : "source";
|
|
29
|
+
}
|
|
30
|
+
function short(v) {
|
|
31
|
+
try {
|
|
32
|
+
if (typeof v === "string")
|
|
33
|
+
return JSON.stringify(v);
|
|
34
|
+
if (v === null || v === undefined || typeof v !== "object")
|
|
35
|
+
return String(v);
|
|
36
|
+
const s = JSON.stringify(v);
|
|
37
|
+
if (s === undefined)
|
|
38
|
+
return Object.prototype.toString.call(v);
|
|
39
|
+
return s.length > 48 ? `${s.slice(0, 47)}…` : s;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return "?";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Upstream cells: eager lens parents unioned with dynamic forward deps. */
|
|
46
|
+
export function upstream(c) {
|
|
47
|
+
const out = [];
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
const push = (n) => {
|
|
50
|
+
if (n instanceof Cell && !seen.has(n)) {
|
|
51
|
+
seen.add(n);
|
|
52
|
+
out.push(n);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
for (let e = edges(erase(c)).parentEdges; e !== undefined; e = e.nextParent)
|
|
56
|
+
push(e.parent);
|
|
57
|
+
for (let l = edges(erase(c)).deps; l !== undefined; l = l.nextDep)
|
|
58
|
+
push(l.dep);
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
/** One-line summary: `name = value [kind]` plus upstream labels, if any. */
|
|
62
|
+
export function explain(c) {
|
|
63
|
+
let v;
|
|
64
|
+
try {
|
|
65
|
+
v = c.peek();
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
v = "?";
|
|
69
|
+
}
|
|
70
|
+
const ups = upstream(c);
|
|
71
|
+
const tail = ups.length > 0 ? ` ← ${ups.map(label).join(", ")}` : "";
|
|
72
|
+
return `${label(c)} = ${short(v)} [${kind(c)}]${tail}`;
|
|
73
|
+
}
|
|
74
|
+
/** Render the upstream graph of `root` as an indented tree (cycle-safe). */
|
|
75
|
+
export function dumpGraph(root, opts = {}) {
|
|
76
|
+
const maxDepth = opts.depth ?? Number.POSITIVE_INFINITY;
|
|
77
|
+
const withValues = opts.values ?? true;
|
|
78
|
+
const lines = [];
|
|
79
|
+
const path = new Set();
|
|
80
|
+
const line = (c, indent) => {
|
|
81
|
+
if (!withValues)
|
|
82
|
+
return `${indent}${label(c)} [${kind(c)}]`;
|
|
83
|
+
let v;
|
|
84
|
+
try {
|
|
85
|
+
v = c.peek();
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
v = "?";
|
|
89
|
+
}
|
|
90
|
+
return `${indent}${label(c)} = ${short(v)} [${kind(c)}]`;
|
|
91
|
+
};
|
|
92
|
+
const walk = (c, indent, depth) => {
|
|
93
|
+
if (path.has(c)) {
|
|
94
|
+
lines.push(`${indent}${label(c)} ↺`); // back-edge into the current path
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
lines.push(line(c, indent));
|
|
98
|
+
if (depth >= maxDepth)
|
|
99
|
+
return;
|
|
100
|
+
path.add(c);
|
|
101
|
+
for (const u of upstream(c))
|
|
102
|
+
walk(u, `${indent} `, depth + 1);
|
|
103
|
+
path.delete(c);
|
|
104
|
+
};
|
|
105
|
+
walk(root, "", 0);
|
|
106
|
+
return lines.join("\n");
|
|
107
|
+
}
|
|
108
|
+
/** Run `fn` and collect the source cells written during it (back-writes included,
|
|
109
|
+
* since a view write commits through its sources' `_writeSource`). */
|
|
110
|
+
export function traceWrites(fn) {
|
|
111
|
+
const writes = [];
|
|
112
|
+
const restore = setCellWriteHook(c => {
|
|
113
|
+
writes.push(c);
|
|
114
|
+
});
|
|
115
|
+
try {
|
|
116
|
+
return { result: fn(), writes };
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
restore();
|
|
120
|
+
}
|
|
121
|
+
}
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,33 +1,28 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { type Counts, counts, resetCounts, snapshotCounts, withCounts } from "./_counts.js";
|
|
2
|
+
export { batch, Cell, type CellOptions, cachedDerive, cell, derive, effect, fieldLens, fieldOf, type Init, type Inner, isCell, isLens, isReadonly, lazy, lens, type Network, network, type Optic, type Read, reader, readNow, SKIP, type Skip, type StatefulBwd, type StatefulBwd1, type StatefulLensSpec, type StatefulLensSpec1, setCellWriteHook, settle, transitiveDeps, untracked, type Val, type Writable, type WritableBrand, } from "./cell.js";
|
|
3
|
+
export { type DumpOpts, dumpGraph, explain, kind as cellKind, label as cellLabel, traceWrites, upstream, } from "./debug.js";
|
|
2
4
|
export { bezier2, bezier3 } from "./derived-geometry.js";
|
|
3
5
|
export * from "./lenses/index.js";
|
|
4
6
|
export { each, type Lifecycle } from "./lifecycle.js";
|
|
7
|
+
export { atKey, compose, iso, optic } from "./optic.js";
|
|
8
|
+
export { at, fields } from "./optics.js";
|
|
9
|
+
export { type Store, store } from "./store.js";
|
|
5
10
|
export { type Equals, type Lerp, type Linear, type Metric, type Pack, type Pivotal, requireEquals, requireLerp, requireLinear, requireMetric, requirePack, requirePivotal, type TraitDict, type Traits, } from "./traits.js";
|
|
6
11
|
export { Anchor, Dir } from "./values/anchor.js";
|
|
7
12
|
export { Audio, type AudioClip, audio, stamp as audioStamp } from "./values/audio.js";
|
|
8
|
-
export * as BoolMath from "./values/bool.js";
|
|
9
13
|
export { Bool, bool } from "./values/bool.js";
|
|
10
|
-
export
|
|
11
|
-
export { Box, box } from "./values/box.js";
|
|
14
|
+
export { Box, box, edgeFrom as boxEdgeFrom, expand as boxExpand, union as boxUnion, } from "./values/box.js";
|
|
12
15
|
export { Canvas, canvas, type Raster, stamp as canvasStamp } from "./values/canvas.js";
|
|
13
|
-
export * as ColorMath from "./values/color.js";
|
|
14
16
|
export { Color, rgb, rgba } from "./values/color.js";
|
|
17
|
+
export { type ColorStop, Colour, Field, type FieldVal, field, type Kind as FieldKind, Scalar, Vector, } from "./values/field.js";
|
|
15
18
|
export { Flags, flags } from "./values/flags.js";
|
|
16
19
|
export { blit as gpuBlit, brush as gpuBrush, copy as gpuCopy, newTex as gpuNewTex, Spring, scratch2 as gpuScratch2, type Tex, } from "./values/gpu.js";
|
|
17
|
-
export
|
|
18
|
-
export { Matrix, matrix, transformBox, transformPoint } from "./values/matrix.js";
|
|
19
|
-
export * as NumMath from "./values/num.js";
|
|
20
|
+
export { compose as matrixCompose, Matrix, matrix, toMatrixString, transformBox, transformPoint, } from "./values/matrix.js";
|
|
20
21
|
export { Num, num } from "./values/num.js";
|
|
21
|
-
export * as PoseMath from "./values/pose.js";
|
|
22
22
|
export { Pose, pose } from "./values/pose.js";
|
|
23
|
-
export * as RangeMath from "./values/range.js";
|
|
24
23
|
export { Range, range, span } from "./values/range.js";
|
|
25
|
-
export * as StrMath from "./values/str.js";
|
|
26
24
|
export { Str, str } from "./values/str.js";
|
|
27
25
|
export { type Codec, enumCodec, numCodec, route, type Slot, slot, strCodec, template, tpl, } from "./values/template.js";
|
|
28
|
-
export * as TransformMath from "./values/transform.js";
|
|
29
26
|
export { Transform, type TransformInit, transform } from "./values/transform.js";
|
|
30
|
-
export * as TriMath from "./values/tri.js";
|
|
31
27
|
export { Tri, tri } from "./values/tri.js";
|
|
32
|
-
export * as VecMath from "./values/vec.js";
|
|
33
28
|
export { type PolarPolicy, polar, tangentPoint, Vec, vec } from "./values/vec.js";
|
package/dist/core/index.js
CHANGED
|
@@ -1,33 +1,28 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { counts, resetCounts, snapshotCounts, withCounts } from "./_counts.js";
|
|
2
|
+
export { batch, Cell, cachedDerive, cell, derive, effect, fieldLens, fieldOf, isCell, isLens, isReadonly, lazy, lens, network, reader, readNow, SKIP, setCellWriteHook, settle, transitiveDeps, untracked, } from "./cell.js";
|
|
3
|
+
export { dumpGraph, explain, kind as cellKind, label as cellLabel, traceWrites, upstream, } from "./debug.js";
|
|
2
4
|
export { bezier2, bezier3 } from "./derived-geometry.js";
|
|
3
5
|
export * from "./lenses/index.js";
|
|
4
6
|
export { each } from "./lifecycle.js";
|
|
7
|
+
export { atKey, compose, iso, optic } from "./optic.js";
|
|
8
|
+
export { at, fields } from "./optics.js";
|
|
9
|
+
export { store } from "./store.js";
|
|
5
10
|
export { requireEquals, requireLerp, requireLinear, requireMetric, requirePack, requirePivotal, } from "./traits.js";
|
|
6
11
|
export { Anchor, Dir } from "./values/anchor.js";
|
|
7
12
|
export { Audio, audio, stamp as audioStamp } from "./values/audio.js";
|
|
8
|
-
export * as BoolMath from "./values/bool.js";
|
|
9
13
|
export { Bool, bool } from "./values/bool.js";
|
|
10
|
-
export
|
|
11
|
-
export { Box, box } from "./values/box.js";
|
|
14
|
+
export { Box, box, edgeFrom as boxEdgeFrom, expand as boxExpand, union as boxUnion, } from "./values/box.js";
|
|
12
15
|
export { Canvas, canvas, stamp as canvasStamp } from "./values/canvas.js";
|
|
13
|
-
export * as ColorMath from "./values/color.js";
|
|
14
16
|
export { Color, rgb, rgba } from "./values/color.js";
|
|
17
|
+
export { Colour, Field, field, Scalar, Vector, } from "./values/field.js";
|
|
15
18
|
export { Flags, flags } from "./values/flags.js";
|
|
16
19
|
export { blit as gpuBlit, brush as gpuBrush, copy as gpuCopy, newTex as gpuNewTex, Spring, scratch2 as gpuScratch2, } from "./values/gpu.js";
|
|
17
|
-
export
|
|
18
|
-
export { Matrix, matrix, transformBox, transformPoint } from "./values/matrix.js";
|
|
19
|
-
export * as NumMath from "./values/num.js";
|
|
20
|
+
export { compose as matrixCompose, Matrix, matrix, toMatrixString, transformBox, transformPoint, } from "./values/matrix.js";
|
|
20
21
|
export { Num, num } from "./values/num.js";
|
|
21
|
-
export * as PoseMath from "./values/pose.js";
|
|
22
22
|
export { Pose, pose } from "./values/pose.js";
|
|
23
|
-
export * as RangeMath from "./values/range.js";
|
|
24
23
|
export { Range, range, span } from "./values/range.js";
|
|
25
|
-
export * as StrMath from "./values/str.js";
|
|
26
24
|
export { Str, str } from "./values/str.js";
|
|
27
25
|
export { enumCodec, numCodec, route, slot, strCodec, template, tpl, } from "./values/template.js";
|
|
28
|
-
export * as TransformMath from "./values/transform.js";
|
|
29
26
|
export { Transform, transform } from "./values/transform.js";
|
|
30
|
-
export * as TriMath from "./values/tri.js";
|
|
31
27
|
export { Tri, tri } from "./values/tri.js";
|
|
32
|
-
export * as VecMath from "./values/vec.js";
|
|
33
28
|
export { polar, tangentPoint, Vec, vec } from "./values/vec.js";
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// All route through the engine's N-input lens path. Stateless-bwd
|
|
6
6
|
// (`(target) => updates`) skips the peek loop on the hot path;
|
|
7
7
|
// stateful-bwd (`(target, vals) => updates`) reads the scratch.
|
|
8
|
+
import { SKIP } from "../cell.js";
|
|
8
9
|
import { Num } from "../values/num.js";
|
|
9
10
|
import { Vec } from "../values/vec.js";
|
|
10
11
|
/** Project `p` into the closed disc of radius `r` centred on `c` (points
|
|
@@ -51,7 +52,7 @@ export function argminNum(inputs, forward, weights, opts = {}) {
|
|
|
51
52
|
const k = dy / denom;
|
|
52
53
|
for (let i = 0; i < n; i++) {
|
|
53
54
|
if (weights[i] === 0) {
|
|
54
|
-
out[i] =
|
|
55
|
+
out[i] = SKIP;
|
|
55
56
|
}
|
|
56
57
|
else {
|
|
57
58
|
out[i] = xs[i] + weights[i] * J[i] * k;
|
|
@@ -103,7 +104,7 @@ export function argminVec(inputs, forward, weights, opts = {}) {
|
|
|
103
104
|
if (Math.abs(det) < 1e-14) {
|
|
104
105
|
// Singular; leave inputs unchanged.
|
|
105
106
|
for (let i = 0; i < n; i++)
|
|
106
|
-
out[i] =
|
|
107
|
+
out[i] = SKIP;
|
|
107
108
|
return out;
|
|
108
109
|
}
|
|
109
110
|
const invA = c / det;
|
|
@@ -114,7 +115,7 @@ export function argminVec(inputs, forward, weights, opts = {}) {
|
|
|
114
115
|
for (let i = 0; i < n; i++) {
|
|
115
116
|
const w = weights[i];
|
|
116
117
|
if (w === 0) {
|
|
117
|
-
out[i] =
|
|
118
|
+
out[i] = SKIP;
|
|
118
119
|
}
|
|
119
120
|
else {
|
|
120
121
|
out[i] = xs[i] + w * (Jx[i] * kx + Jy[i] * ky);
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// (bestFitLine, bestFitCircle, pca, total). All exact, idempotent,
|
|
11
11
|
// cross-channel invariant by construction, on the same `Cls.lens`
|
|
12
12
|
// machinery — no engine changes.
|
|
13
|
-
import { mean, Num, Vec, } from "../index.js";
|
|
13
|
+
import { mean, Num, SKIP, Vec, } from "../index.js";
|
|
14
14
|
import { continuous, remember } from "./memory.js";
|
|
15
15
|
// Pivotal trait lookup via the value class's `static traits.pivotal` slot.
|
|
16
16
|
// biome-ignore lint/suspicious/noExplicitAny: dynamic trait lookup
|
|
@@ -50,7 +50,7 @@ export function rotateAbout(points, pivot) {
|
|
|
50
50
|
const rx0 = vals[0].x - p.x;
|
|
51
51
|
const ry0 = vals[0].y - p.y;
|
|
52
52
|
if (rx0 * rx0 + ry0 * ry0 < 1e-24) {
|
|
53
|
-
return vals.map(() =>
|
|
53
|
+
return vals.map(() => SKIP);
|
|
54
54
|
}
|
|
55
55
|
const oldθ = Math.atan2(ry0, rx0);
|
|
56
56
|
const dθ = target - oldθ;
|
|
@@ -96,11 +96,11 @@ export function scaleAbout(points, pivot) {
|
|
|
96
96
|
// re-projects to the current radius and is absorbed (sources put).
|
|
97
97
|
const rNow = Math.hypot(vals[0].x - p.x, vals[0].y - p.y);
|
|
98
98
|
if (Math.abs(target) === rNow)
|
|
99
|
-
return { updates: vals.map(() =>
|
|
99
|
+
return { updates: vals.map(() => SKIP), complement: c };
|
|
100
100
|
const d0 = c.devs[0];
|
|
101
101
|
const r0 = Math.hypot(d0.x, d0.y);
|
|
102
102
|
if (r0 < 1e-12)
|
|
103
|
-
return { updates: vals.map(() =>
|
|
103
|
+
return { updates: vals.map(() => SKIP), complement: c };
|
|
104
104
|
const k = target / r0;
|
|
105
105
|
const out = vals.map((v, i) => ({
|
|
106
106
|
...v,
|
|
@@ -299,7 +299,7 @@ export function pca(points) {
|
|
|
299
299
|
const rotation = Num.lens(points, (vals) => decompose(vals)?.θ ?? 0, (target, vals) => {
|
|
300
300
|
const d = decompose(vals);
|
|
301
301
|
if (!d)
|
|
302
|
-
return vals.map(() =>
|
|
302
|
+
return vals.map(() => SKIP);
|
|
303
303
|
const dθ = target - d.θ;
|
|
304
304
|
const cos = Math.cos(dθ);
|
|
305
305
|
const sin = Math.sin(dθ);
|
|
@@ -382,10 +382,15 @@ export function pca(points) {
|
|
|
382
382
|
// Lossy magnitude view: a same-magnitude target re-projects to
|
|
383
383
|
// the current axis length and is absorbed (cluster left put).
|
|
384
384
|
if (Math.abs(target) === c.lenThis)
|
|
385
|
-
return { updates: vals.map(() =>
|
|
386
|
-
// Non-degenerate fast path: scale current cluster along axis.
|
|
385
|
+
return { updates: vals.map(() => SKIP), complement: c };
|
|
386
|
+
// Non-degenerate fast path: scale current cluster along axis. The scale
|
|
387
|
+
// sets the axis length to |target|, so the complement is consistent
|
|
388
|
+
// without a post-write `step` (the engine no longer re-steps own writes).
|
|
387
389
|
const k = target / c.lenThis;
|
|
388
|
-
return {
|
|
390
|
+
return {
|
|
391
|
+
updates: scaleAlongAxis(vals, d.cx, d.cy, c.uX, c.uY, k),
|
|
392
|
+
complement: { ...c, lenThis: Math.abs(target) },
|
|
393
|
+
};
|
|
389
394
|
}
|
|
390
395
|
// Degenerate: reconstruct from complement. Centroid still
|
|
391
396
|
// derivable from current source (mean translates always work).
|
|
@@ -403,7 +408,7 @@ export function pca(points) {
|
|
|
403
408
|
const b = c.projOther[i] * c.lenOther;
|
|
404
409
|
out[i] = { x: cx + a * c.uX + b * c.vX, y: cy + a * c.uY + b * c.vY };
|
|
405
410
|
}
|
|
406
|
-
return { updates: out, complement: c };
|
|
411
|
+
return { updates: out, complement: { ...c, lenThis: Math.abs(target) } };
|
|
407
412
|
},
|
|
408
413
|
});
|
|
409
414
|
};
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// about the centroid), so cross-channel invariance is EXACT and one
|
|
7
7
|
// write lands in O(K). For the generic numerical N→M escape hatch (when
|
|
8
8
|
// no closed form fits) see `factor` in `typed-factor.ts`.
|
|
9
|
-
import { Num, Vec } from "../index.js";
|
|
9
|
+
import { Num, SKIP, Vec } from "../index.js";
|
|
10
10
|
// meanDiff — M=2 isomorphism baseline.
|
|
11
11
|
//
|
|
12
12
|
// (a, b) → ((a+b)/2, a−b). Square full-rank linear lens; bwd is the
|
|
@@ -84,7 +84,7 @@ export function procrustes(points) {
|
|
|
84
84
|
const ry0 = vals[0].y - cy;
|
|
85
85
|
if (rx0 * rx0 + ry0 * ry0 < 1e-24) {
|
|
86
86
|
// Collapsed cluster; no angle to rotate from.
|
|
87
|
-
return vals.map(() =>
|
|
87
|
+
return vals.map(() => SKIP);
|
|
88
88
|
}
|
|
89
89
|
const oldθ = Math.atan2(ry0, rx0);
|
|
90
90
|
const dθ = target - oldθ;
|
|
@@ -130,7 +130,7 @@ export function procrustes(points) {
|
|
|
130
130
|
const d0 = c.devs[0];
|
|
131
131
|
const r0 = Math.hypot(d0.x, d0.y);
|
|
132
132
|
if (r0 < 1e-12)
|
|
133
|
-
return { updates: vals.map(() =>
|
|
133
|
+
return { updates: vals.map(() => SKIP), complement: c };
|
|
134
134
|
const k = target / r0;
|
|
135
135
|
const out = c.devs.map(d => ({ x: cen.x + k * d.x, y: cen.y + k * d.y }));
|
|
136
136
|
return { updates: out, complement: c };
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// (2) Bezier gestalt handles ({start, end, startTangent, endTangent}).
|
|
7
7
|
// (3) Time-series ({mean, slope}) over (i, value) samples.
|
|
8
8
|
// All exact, idempotent, cross-channel invariant by construction.
|
|
9
|
-
import { Num, reader, Vec, } from "../index.js";
|
|
9
|
+
import { Num, reader, SKIP, Vec, } from "../index.js";
|
|
10
10
|
import { remember } from "./memory.js";
|
|
11
11
|
// Generic Linear-trait aggregates.
|
|
12
12
|
//
|
|
@@ -107,9 +107,9 @@ export function mix(weights, branches) {
|
|
|
107
107
|
const { w, sumSq } = readW();
|
|
108
108
|
const delta = lin.sub(target, combine(vals, w));
|
|
109
109
|
if (sumSq < 1e-12)
|
|
110
|
-
return vals.map(() =>
|
|
110
|
+
return vals.map(() => SKIP);
|
|
111
111
|
const inv = 1 / sumSq;
|
|
112
|
-
return vals.map((v, i) => w[i] === 0 ?
|
|
112
|
+
return vals.map((v, i) => w[i] === 0 ? SKIP : lin.add(v, lin.scale(delta, w[i] * inv)));
|
|
113
113
|
});
|
|
114
114
|
}
|
|
115
115
|
/** Two-branch router (mix simplex *vertex*): reads the live branch, writes
|
|
@@ -187,8 +187,8 @@ export function bezierGestalt(p0, p1, p2, p3) {
|
|
|
187
187
|
const dy = target.y - vals[1].y;
|
|
188
188
|
return [{ x: vals[0].x + dx, y: vals[0].y + dy }, target];
|
|
189
189
|
});
|
|
190
|
-
const startTangent = Vec.lens([p0, p1], (vals) => ({ x: vals[1].x - vals[0].x, y: vals[1].y - vals[0].y }), (target, vals) => [
|
|
191
|
-
const endTangent = Vec.lens([p2, p3], (vals) => ({ x: vals[1].x - vals[0].x, y: vals[1].y - vals[0].y }), (target, vals) => [{ x: vals[1].x - target.x, y: vals[1].y - target.y },
|
|
190
|
+
const startTangent = Vec.lens([p0, p1], (vals) => ({ x: vals[1].x - vals[0].x, y: vals[1].y - vals[0].y }), (target, vals) => [SKIP, { x: vals[0].x + target.x, y: vals[0].y + target.y }]);
|
|
191
|
+
const endTangent = Vec.lens([p2, p3], (vals) => ({ x: vals[1].x - vals[0].x, y: vals[1].y - vals[0].y }), (target, vals) => [{ x: vals[1].x - target.x, y: vals[1].y - target.y }, SKIP]);
|
|
192
192
|
return { start, end, startTangent, endTangent };
|
|
193
193
|
}
|
|
194
194
|
// Time-series aggregates.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// geometry.ts — geometric lens building blocks over the N-input
|
|
2
2
|
// `Cls.lens` / `Cls.derive` forms. All are a few lines on top of the engine.
|
|
3
|
+
import { SKIP } from "../cell.js";
|
|
3
4
|
import { Num } from "../values/num.js";
|
|
4
5
|
import { Vec } from "../values/vec.js";
|
|
5
6
|
import { rotateAbout } from "./closed-form-policies.js";
|
|
@@ -36,7 +37,7 @@ export function reflection(point, axisStart, axisEnd) {
|
|
|
36
37
|
const projY = a.y + t * dy;
|
|
37
38
|
return { x: 2 * projX - p.x, y: 2 * projY - p.y };
|
|
38
39
|
};
|
|
39
|
-
return Vec.lens([point, axisStart, axisEnd], vals => reflect(vals[0], vals[1], vals[2]), (target, vals) => [reflect(target, vals[1], vals[2]),
|
|
40
|
+
return Vec.lens([point, axisStart, axisEnd], vals => reflect(vals[0], vals[1], vals[2]), (target, vals) => [reflect(target, vals[1], vals[2]), SKIP, SKIP]);
|
|
40
41
|
}
|
|
41
42
|
/** Lerp between two Vecs at parameter `t`. Writing the interpolated point
|
|
42
43
|
* shifts both endpoints rigidly (preserving t). */
|
|
@@ -48,7 +49,7 @@ export function vecLerp(a, b, t) {
|
|
|
48
49
|
const [av, bv, tv] = vals;
|
|
49
50
|
const dx = target.x - (av.x + (bv.x - av.x) * tv);
|
|
50
51
|
const dy = target.y - (av.y + (bv.y - av.y) * tv);
|
|
51
|
-
return [{ x: av.x + dx, y: av.y + dy }, { x: bv.x + dx, y: bv.y + dy },
|
|
52
|
+
return [{ x: av.x + dx, y: av.y + dy }, { x: bv.x + dx, y: bv.y + dy }, SKIP];
|
|
52
53
|
});
|
|
53
54
|
}
|
|
54
55
|
/** Sum of two nums; writing the sum splits the delta equally between
|
|
@@ -77,23 +78,21 @@ export function clampedMean(parents, lo, hi) {
|
|
|
77
78
|
const n = parents.length;
|
|
78
79
|
const inv = 1 / n;
|
|
79
80
|
return Num.lens(parents, vals => {
|
|
80
|
-
const arr = vals;
|
|
81
81
|
let s = 0;
|
|
82
82
|
for (let i = 0; i < n; i++)
|
|
83
|
-
s +=
|
|
83
|
+
s += vals[i];
|
|
84
84
|
const m = s * inv;
|
|
85
85
|
return m < lo ? lo : m > hi ? hi : m;
|
|
86
86
|
}, (target, vals) => {
|
|
87
|
-
const arr = vals;
|
|
88
87
|
const clamped = target < lo ? lo : target > hi ? hi : target;
|
|
89
88
|
let s = 0;
|
|
90
89
|
for (let i = 0; i < n; i++)
|
|
91
|
-
s +=
|
|
90
|
+
s += vals[i];
|
|
92
91
|
const cur = s * inv;
|
|
93
92
|
const delta = clamped - cur;
|
|
94
93
|
const out = new Array(n);
|
|
95
94
|
for (let i = 0; i < n; i++)
|
|
96
|
-
out[i] =
|
|
95
|
+
out[i] = vals[i] + delta;
|
|
97
96
|
return out;
|
|
98
97
|
});
|
|
99
98
|
}
|
|
@@ -4,4 +4,5 @@ export { bbox, meanDiff, procrustes } from "./decompositions.js";
|
|
|
4
4
|
export { bezierGestalt, crossfade, mean, meanSpread, mix, select, spread, timeSeries, } from "./domain-aggregates.js";
|
|
5
5
|
export { angle, clampedMean, diff, distance, pulleySum, reflection, vecLerp } from "./geometry.js";
|
|
6
6
|
export { type ContinuousOpts, continuous, type RememberOpts, remember, } from "./memory.js";
|
|
7
|
+
export { type ClosestOpts, hullWeights, nearestIndex } from "./snap.js";
|
|
7
8
|
export { bundle, type FactorOpts, type FactorResult, factor, factorTuple, type OutputSpec, type PackedInput, } from "./typed-factor.js";
|
|
@@ -4,4 +4,5 @@ export { bbox, meanDiff, procrustes } from "./decompositions.js";
|
|
|
4
4
|
export { bezierGestalt, crossfade, mean, meanSpread, mix, select, spread, timeSeries, } from "./domain-aggregates.js";
|
|
5
5
|
export { angle, clampedMean, diff, distance, pulleySum, reflection, vecLerp } from "./geometry.js";
|
|
6
6
|
export { continuous, remember, } from "./memory.js";
|
|
7
|
+
export { hullWeights, nearestIndex } from "./snap.js";
|
|
7
8
|
export { bundle, factor, factorTuple, } from "./typed-factor.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Cell, Num, type Traits, type Writable } from "../index.js";
|
|
1
|
+
import { type Cell, Num, type Skip, type Traits, type Writable } from "../index.js";
|
|
2
2
|
/** Options for {@link remember}. `anchor` is the fixed point sources scale
|
|
3
3
|
* about (a pivot, or the live centroid); `feature` is the writable scalar
|
|
4
4
|
* (a radius, mean distance, or sum). */
|
|
@@ -38,7 +38,7 @@ export interface ContinuousOpts<T> {
|
|
|
38
38
|
};
|
|
39
39
|
/** Realize `target` (already unwrapped, absolute) onto the sources,
|
|
40
40
|
* given the `current` unwrapped reading (for a delta). */
|
|
41
|
-
apply: (target: number, vals: readonly T[], current: number) => readonly (T |
|
|
41
|
+
apply: (target: number, vals: readonly T[], current: number) => readonly (T | Skip)[];
|
|
42
42
|
}
|
|
43
43
|
/** Continuous (winding-aware) lens over a cyclic reading. The complement
|
|
44
44
|
* tracks the last emitted value and unwraps each raw reading to the
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// unwraps the raw reading to the nearest sheet, so the
|
|
16
16
|
// view never tears at a branch cut. Covers the eigenvector
|
|
17
17
|
// angle of bestFitLine; the primitive behind winding.
|
|
18
|
-
import { Num } from "../index.js";
|
|
18
|
+
import { Num, SKIP } from "../index.js";
|
|
19
19
|
/** Scalar shape-memory lens. Reads `feature(sources)`; writing it scales
|
|
20
20
|
* the cluster about `anchor` so the new feature matches, reinflating the
|
|
21
21
|
* remembered shape when the cluster has collapsed onto the anchor. The
|
|
@@ -59,7 +59,7 @@ export function remember(sources, opts) {
|
|
|
59
59
|
// Magnitude is lossy (|−f| = f): a same-magnitude target re-projects
|
|
60
60
|
// to the current feature, so the cluster is left put.
|
|
61
61
|
if (magnitude && Math.abs(target) === f) {
|
|
62
|
-
return { updates: vals.map(() =>
|
|
62
|
+
return { updates: vals.map(() => SKIP), complement: c };
|
|
63
63
|
}
|
|
64
64
|
if (f > eps) {
|
|
65
65
|
const k = target / f;
|
|
@@ -94,7 +94,7 @@ export function continuous(sources, opts) {
|
|
|
94
94
|
bwd: (target, vals, c) => {
|
|
95
95
|
const r = raw(vals);
|
|
96
96
|
if (!r.defined)
|
|
97
|
-
return { updates: vals.map(() =>
|
|
97
|
+
return { updates: vals.map(() => SKIP), complement: { prev: target } };
|
|
98
98
|
const current = unwrap(r.value, c.prev);
|
|
99
99
|
return { updates: apply(target, vals, current), complement: { prev: target } };
|
|
100
100
|
},
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Cell, type Read } from "../cell.js";
|
|
2
|
+
type V = {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
};
|
|
6
|
+
/** Convex-hull barycentric weights of `q` over `pts` (Σ = 1, all ≥ 0,
|
|
7
|
+
* clamped to the hull). Closed form for K ≤ 3; Frank–Wolfe for K > 3. */
|
|
8
|
+
export declare function hullWeights(q: V, pts: readonly V[]): number[];
|
|
9
|
+
export interface ClosestOpts {
|
|
10
|
+
/** Hysteresis margin (px): the current pick is kept until a rival is
|
|
11
|
+
* nearer by more than this. Dragology's stickiness. Default 0. */
|
|
12
|
+
sticky?: number;
|
|
13
|
+
}
|
|
14
|
+
/** Index of the candidate nearest `pointer`, with hysteresis. Read-only
|
|
15
|
+
* selection: the stickiness state lives in the lens complement (the
|
|
16
|
+
* sanctioned place for path-dependence), so reads stay pure. */
|
|
17
|
+
export declare function nearestIndex(pointer: Read<V>, candidates: readonly Read<V>[], opts?: ClosestOpts): Cell<number>;
|
|
18
|
+
export {};
|