@graphty/graphty-element 2.2.5 → 2.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/ai.js +115 -222
- package/dist/catalog.js +56 -55
- package/dist/chunks/{AiManager-Bd_r1Hei.js → AiManager-BBmGJbH4.js} +793 -654
- package/dist/chunks/{DataSource-Dag8H5US.js → DataSource-OeN3NeyD.js} +1 -1
- package/dist/chunks/{GraphSession-mfo75G0q.js → GraphSession-Bef1AYw9.js} +2136 -2104
- package/dist/chunks/{GraphStyle-D0PXnZKu.js → GraphStyle-Cwr55SAE.js} +5 -2
- package/dist/chunks/{VoiceInputAdapter-DszYl6Ha.js → VoiceInputAdapter-Dr9Gcmds.js} +1 -1
- package/dist/chunks/{XRPivotCameraController-BdoMFcON.js → XRPivotCameraController-BbfgZWpS.js} +1 -1
- package/dist/chunks/algorithms-CpX56sUB.js +3482 -0
- package/dist/chunks/{capability-check-CdoqmrF0.js → capability-check-Blhb2aBB.js} +1 -1
- package/dist/chunks/{detect-LAOOaxY_.js → detect-Cqwshr9a.js} +1 -1
- package/dist/chunks/{format-detection-a0bD5PIB.js → format-detection-BXGO1lSn.js} +1 -1
- package/dist/chunks/{index-BY1gnMiZ.js → index-C0mIoumR.js} +2258 -2129
- package/dist/chunks/optionsFromZod-17lkrAJs.js +2565 -0
- package/dist/chunks/paletteRegistry-x7WOEKZY.js +1153 -0
- package/dist/chunks/scales-BRwl51k8.js +3047 -0
- package/dist/custom-elements.json +1 -1
- package/dist/extend.js +42 -42
- package/dist/graphty-catalog.json +1 -1
- package/dist/graphty.bundle.js +25816 -25456
- package/dist/graphty.js +29 -29
- package/dist/schema.js +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/session.js +28 -29
- package/dist/src/Graph.d.ts +33 -3
- package/dist/src/algorithms/metrics/context.d.ts +7 -5
- package/dist/src/algorithms/results/types.d.ts +17 -1
- package/dist/src/camera/builtins.d.ts +14 -1
- package/dist/src/camera/types.d.ts +7 -0
- package/dist/src/cameras/CameraManager.d.ts +13 -0
- package/dist/src/cameras/OrbitCameraController.d.ts +9 -0
- package/dist/src/catalog/types.d.ts +10 -0
- package/dist/src/config/GraphStyle.d.ts +5 -1
- package/dist/src/config/StyleTemplate.d.ts +2 -2
- package/dist/src/graphty-element.d.ts +11 -6
- package/dist/src/managers/StylePainter.d.ts +9 -0
- package/dist/src/managers/UpdateManager.d.ts +5 -0
- package/dist/src/session/results/index.d.ts +1 -1
- package/dist/src/session/results/statistics.d.ts +8 -1
- package/dist/src/session/results/types.d.ts +33 -0
- package/dist/src/session/selection/targets.d.ts +4 -1
- package/dist/src/session/styles/predicate.d.ts +26 -1
- package/dist/src/session/styles/repaint.d.ts +11 -0
- package/dist/src/session/styles/selector.d.ts +13 -1
- package/dist/src/session/styles/sources.d.ts +9 -0
- package/package.json +1 -1
- package/dist/chunks/Algorithm-RQ629NLb.js +0 -494
- package/dist/chunks/cameras-ii4vngYY.js +0 -435
- package/dist/chunks/paletteRegistry-YSpPryiT.js +0 -3164
- package/dist/chunks/scales-DOpwlWuz.js +0 -6086
|
@@ -115,6 +115,19 @@ export interface SelectorSource {
|
|
|
115
115
|
* @returns The indices, or undefined when the column cannot be enumerated.
|
|
116
116
|
*/
|
|
117
117
|
readonly measured?: (path: Path, target: SelectorTarget) => ArrayLike<number> | undefined;
|
|
118
|
+
/**
|
|
119
|
+
* The lowest value in the top `n` of one run column, cut only between tie groups (see
|
|
120
|
+
* `RunResult.top`), or undefined when nothing is taken or the column is not a ranked run
|
|
121
|
+
* field for this kind of element. Absent, a `{match:"top"}` selector is refused.
|
|
122
|
+
*
|
|
123
|
+
* Asked once per element, so it must answer from something already computed: a session
|
|
124
|
+
* reads it off the run's result, which keeps the answer per field and `n`.
|
|
125
|
+
* @param path - The column path, `results.<run>.<field>`.
|
|
126
|
+
* @param target - Whether the asking layer paints nodes or edges.
|
|
127
|
+
* @param n - The most elements the top may hold.
|
|
128
|
+
* @returns The cut, or undefined.
|
|
129
|
+
*/
|
|
130
|
+
readonly topCut?: (path: Path, target: SelectorTarget, n: number) => number | undefined;
|
|
118
131
|
}
|
|
119
132
|
/**
|
|
120
133
|
* One target's half of a {@link SelectorSource}, resolved once so the predicate never chooses.
|
|
@@ -160,7 +173,7 @@ export type ElementPredicate = (index: number) => boolean;
|
|
|
160
173
|
/** A selector, reduced to the test a repaint runs and the columns that test reads. */
|
|
161
174
|
export interface CompiledSelector {
|
|
162
175
|
/** Which selector kind this was compiled from. */
|
|
163
|
-
readonly match: "everything" | "expression" | "has" | "ids";
|
|
176
|
+
readonly match: "everything" | "expression" | "has" | "ids" | "top";
|
|
164
177
|
/** Which kind of element it speaks about. */
|
|
165
178
|
readonly target: SelectorTarget;
|
|
166
179
|
/**
|
|
@@ -231,6 +244,18 @@ export declare function hasPredicate(columns: ElementColumns, path: Path): Eleme
|
|
|
231
244
|
* @returns The test.
|
|
232
245
|
*/
|
|
233
246
|
export declare function idsPredicate(columns: ElementColumns, ids: ReadonlySet<EdgeId | NodeId>): ElementPredicate;
|
|
247
|
+
/**
|
|
248
|
+
* The predicate for `{match:"top"}`: the element's value is at or above the top's cut.
|
|
249
|
+
*
|
|
250
|
+
* The cut is asked for per element rather than settled here, because a run that finishes or
|
|
251
|
+
* re-runs after the layer was added publishes a new ranking, and a cut captured now would go on
|
|
252
|
+
* painting the old top.
|
|
253
|
+
* @param columns - Where to read values.
|
|
254
|
+
* @param path - The column path.
|
|
255
|
+
* @param cutOf - The lowest value in the top, or undefined when nothing is in it.
|
|
256
|
+
* @returns The test.
|
|
257
|
+
*/
|
|
258
|
+
export declare function topPredicate(columns: ElementColumns, path: Path, cutOf: () => number | undefined): ElementPredicate;
|
|
234
259
|
/**
|
|
235
260
|
* Parse and compile `{match:"expression"}`.
|
|
236
261
|
*
|
|
@@ -211,6 +211,17 @@ export interface ElementPaint {
|
|
|
211
211
|
* @returns A function that stops the notifications.
|
|
212
212
|
*/
|
|
213
213
|
onPainted(listener: () => void): () => void;
|
|
214
|
+
/**
|
|
215
|
+
* Whether a pass has been asked for and has not finished yet.
|
|
216
|
+
*
|
|
217
|
+
* A pass YIELDS TO THE EVENT LOOP and waits behind the pass in front of it, so between the
|
|
218
|
+
* edit that asks for it and the announcement that ends it there are frames -- as many as the
|
|
219
|
+
* machine is slow. Nothing is in {@link ElementPaint.lastPainted} for those frames, and a
|
|
220
|
+
* renderer that asked only whether paint was waiting to be drawn would call the picture
|
|
221
|
+
* finished, and frame the camera on it, while a node's new size was still on its way.
|
|
222
|
+
* @returns True from the moment a pass is requested until it has announced what it painted.
|
|
223
|
+
*/
|
|
224
|
+
painting(): boolean;
|
|
214
225
|
/**
|
|
215
226
|
* The layers the last pass could not paint, and why.
|
|
216
227
|
* @returns The problems, emptied at the start of every pass.
|
|
@@ -68,6 +68,17 @@ export type Selector =
|
|
|
68
68
|
readonly match: "ids";
|
|
69
69
|
readonly nodes?: readonly NodeId[];
|
|
70
70
|
readonly edges?: readonly EdgeId[];
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The top `n` elements by one run field, `results.<run>.<field>`, cut only between tie
|
|
74
|
+
* groups: a group of equal values is painted whole, and only when all of it fits inside `n`.
|
|
75
|
+
* So a layer never paints more than `n` elements, and paints none on a graph whose highest
|
|
76
|
+
* value is shared by more than `n`. `RunResult.top` is the same cut with its reason.
|
|
77
|
+
*/
|
|
78
|
+
| {
|
|
79
|
+
readonly match: "top";
|
|
80
|
+
readonly path: Path;
|
|
81
|
+
readonly n: number;
|
|
71
82
|
};
|
|
72
83
|
/**
|
|
73
84
|
* Turn a selector into the predicate a repaint runs.
|
|
@@ -81,6 +92,7 @@ export type Selector =
|
|
|
81
92
|
* @returns The compiled selector: its test, and the columns that test reads.
|
|
82
93
|
* @throws A `GraphtyError` with code `E_BAD_SELECTOR` when the selector's shape or its
|
|
83
94
|
* expression is wrong, `E_SELECTOR_EMPTY` when a selector is empty, and `E_UNSUPPORTED`
|
|
84
|
-
* when an `ids` selector is offered to a session that cannot say which id sits at which row
|
|
95
|
+
* when an `ids` selector is offered to a session that cannot say which id sits at which row,
|
|
96
|
+
* or a `top` selector to one that cannot rank a run's column.
|
|
85
97
|
*/
|
|
86
98
|
export declare function compileSelector(selector: Selector, target: SelectorTarget, source: SelectorSource): CompiledSelector;
|
|
@@ -131,6 +131,15 @@ export interface SessionSelectorSource extends SelectorSource {
|
|
|
131
131
|
* @returns The indices, ascending, or undefined when the column cannot be enumerated.
|
|
132
132
|
*/
|
|
133
133
|
readonly measured: (path: Path, target: SelectorTarget) => ArrayLike<number> | undefined;
|
|
134
|
+
/**
|
|
135
|
+
* The lowest value in the top `n` of a run's column, from `RunResult.top`, which keeps it.
|
|
136
|
+
* @param path - The column path, `results.<run>.<field>`.
|
|
137
|
+
* @param target - Whether the asking layer paints nodes or edges.
|
|
138
|
+
* @param n - The most elements the top may hold.
|
|
139
|
+
* @returns The cut, or undefined when nothing is taken or the path names no numeric field of
|
|
140
|
+
* this kind of element.
|
|
141
|
+
*/
|
|
142
|
+
readonly topCut: (path: Path, target: SelectorTarget, n: number) => number | undefined;
|
|
134
143
|
}
|
|
135
144
|
/**
|
|
136
145
|
* The id of the node at one end of an edge, for the attribute keys that name an endpoint.
|
package/package.json
CHANGED
|
@@ -1,494 +0,0 @@
|
|
|
1
|
-
import { q as C } from "./GraphtyLogger-5KEttFUo.js";
|
|
2
|
-
import { K as $, f as N } from "./types-B7bX5c0K.js";
|
|
3
|
-
import { G as d } from "./GraphtyError-BwcnblTH.js";
|
|
4
|
-
import { Graph as _, accelerated as y } from "@graphty/algorithms";
|
|
5
|
-
import { INVALID_INDEX as w } from "@graphty/graph-format";
|
|
6
|
-
const p = C({
|
|
7
|
-
kind: "camera",
|
|
8
|
-
idOf: (e) => e.descriptor.id,
|
|
9
|
-
descriptorOf: (e) => e.descriptor,
|
|
10
|
-
implementationOf: (e) => e.compute,
|
|
11
|
-
builtInIds: () => $
|
|
12
|
-
});
|
|
13
|
-
function K(e, t) {
|
|
14
|
-
const s = e.descriptor;
|
|
15
|
-
if (s === void 0 || typeof s != "object")
|
|
16
|
-
throw new d({
|
|
17
|
-
code: "E_BAD_COMMAND",
|
|
18
|
-
message: "registerCameraView takes a camera view with a descriptor",
|
|
19
|
-
source: "registry",
|
|
20
|
-
details: { kind: "camera", field: "descriptor" }
|
|
21
|
-
});
|
|
22
|
-
if (!Array.isArray(s.modes) || s.modes.length === 0)
|
|
23
|
-
throw new d({
|
|
24
|
-
code: "E_BAD_COMMAND",
|
|
25
|
-
message: `the camera view "${String(s.id)}" declares no drawing modes, so nothing could ever offer it: a view says where it works with \`modes\`, and the element refuses the rest`,
|
|
26
|
-
source: "registry",
|
|
27
|
-
details: { kind: "camera", name: String(s.id), field: "modes" }
|
|
28
|
-
});
|
|
29
|
-
if (!Array.isArray(s.options))
|
|
30
|
-
throw new d({
|
|
31
|
-
code: "E_BAD_COMMAND",
|
|
32
|
-
message: `the camera view "${String(s.id)}" declares no options list. A view that takes no configuration declares an empty one, so a form has something to render and the element has something to check a caller's values against`,
|
|
33
|
-
source: "registry",
|
|
34
|
-
details: { kind: "camera", name: String(s.id), field: "options" }
|
|
35
|
-
});
|
|
36
|
-
if (typeof e.compute != "function")
|
|
37
|
-
throw new d({
|
|
38
|
-
code: "E_BAD_COMMAND",
|
|
39
|
-
message: `the camera view "${String(s.id)}" was registered without a compute function`,
|
|
40
|
-
source: "registry",
|
|
41
|
-
details: { kind: "camera", name: String(s.id), field: "compute" }
|
|
42
|
-
});
|
|
43
|
-
p.register(e, t);
|
|
44
|
-
}
|
|
45
|
-
function z() {
|
|
46
|
-
return p.descriptors();
|
|
47
|
-
}
|
|
48
|
-
function W(e) {
|
|
49
|
-
return p.byId(e);
|
|
50
|
-
}
|
|
51
|
-
function Y() {
|
|
52
|
-
p.clearForTesting();
|
|
53
|
-
}
|
|
54
|
-
const I = ["forceAtlas2", "fruchtermanReingold", "springElectrical", "release"], k = [
|
|
55
|
-
"pageRank",
|
|
56
|
-
"sssp",
|
|
57
|
-
"breadthFirstSearch",
|
|
58
|
-
"connectedComponents",
|
|
59
|
-
"weaklyConnectedComponents",
|
|
60
|
-
"minimumSpanningTree"
|
|
61
|
-
];
|
|
62
|
-
function H(e) {
|
|
63
|
-
const t = {
|
|
64
|
-
kind: e.backend
|
|
65
|
-
};
|
|
66
|
-
for (const s of I) {
|
|
67
|
-
const r = e[s];
|
|
68
|
-
typeof r == "function" && (t[s] = r.bind(e));
|
|
69
|
-
}
|
|
70
|
-
return t;
|
|
71
|
-
}
|
|
72
|
-
function R(e) {
|
|
73
|
-
const t = {
|
|
74
|
-
kind: e.backend
|
|
75
|
-
};
|
|
76
|
-
for (const s of k) {
|
|
77
|
-
const r = e[s];
|
|
78
|
-
typeof r == "function" && (t[s] = r.bind(e));
|
|
79
|
-
}
|
|
80
|
-
return t;
|
|
81
|
-
}
|
|
82
|
-
const D = ["auto", "off", "required"], Z = "auto";
|
|
83
|
-
function X(e) {
|
|
84
|
-
return typeof e == "string" && D.includes(e);
|
|
85
|
-
}
|
|
86
|
-
const M = "f64", J = "f32", Q = "acceleration.minNodes", ee = 0, g = C({
|
|
87
|
-
kind: "algorithm",
|
|
88
|
-
idOf: (e) => e.descriptor.key,
|
|
89
|
-
descriptorOf: (e) => e.descriptor,
|
|
90
|
-
implementationOf: (e) => e.descriptor,
|
|
91
|
-
builtInIds: () => N
|
|
92
|
-
});
|
|
93
|
-
function T(e, t) {
|
|
94
|
-
if (e.descriptor.key !== e.type)
|
|
95
|
-
throw new d({
|
|
96
|
-
code: "E_BAD_COMMAND",
|
|
97
|
-
message: `the algorithm registered as "${e.namespace}:${e.type}" publishes the catalogue key "${e.descriptor.key}". An algorithm has one name: make "descriptor.key" equal "static type".`,
|
|
98
|
-
source: "registry",
|
|
99
|
-
details: {
|
|
100
|
-
kind: "algorithm",
|
|
101
|
-
field: "descriptor.key",
|
|
102
|
-
key: e.descriptor.key,
|
|
103
|
-
type: e.type,
|
|
104
|
-
namespace: e.namespace
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
g.register(e, t);
|
|
108
|
-
}
|
|
109
|
-
function te() {
|
|
110
|
-
return g.descriptors();
|
|
111
|
-
}
|
|
112
|
-
function se(e) {
|
|
113
|
-
return g.byId(e);
|
|
114
|
-
}
|
|
115
|
-
function re() {
|
|
116
|
-
g.clearForTesting();
|
|
117
|
-
}
|
|
118
|
-
class a extends Error {
|
|
119
|
-
/**
|
|
120
|
-
* Creates an option validation error
|
|
121
|
-
* @param optionKey - The key of the option that failed validation
|
|
122
|
-
* @param message - The validation error message
|
|
123
|
-
*/
|
|
124
|
-
constructor(t, s) {
|
|
125
|
-
super(`Option '${t}': ${s}`), this.optionKey = t, this.name = "OptionValidationError";
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
function v(e, t, s) {
|
|
129
|
-
if (t == null) {
|
|
130
|
-
if (s.required)
|
|
131
|
-
throw new a(e, "is required but was not provided");
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
switch (s.type) {
|
|
135
|
-
case "number":
|
|
136
|
-
A(e, t, s, !1);
|
|
137
|
-
break;
|
|
138
|
-
case "integer":
|
|
139
|
-
A(e, t, s, !0);
|
|
140
|
-
break;
|
|
141
|
-
case "boolean":
|
|
142
|
-
if (typeof t != "boolean")
|
|
143
|
-
throw new a(e, `must be a boolean, got ${typeof t}`);
|
|
144
|
-
break;
|
|
145
|
-
case "string":
|
|
146
|
-
if (typeof t != "string")
|
|
147
|
-
throw new a(e, `must be a string, got ${typeof t}`);
|
|
148
|
-
break;
|
|
149
|
-
case "select":
|
|
150
|
-
L(e, t, s);
|
|
151
|
-
break;
|
|
152
|
-
case "nodeId":
|
|
153
|
-
if (typeof t != "string" && typeof t != "number")
|
|
154
|
-
throw new a(e, `must be a string or number (node ID), got ${typeof t}`);
|
|
155
|
-
break;
|
|
156
|
-
default:
|
|
157
|
-
throw new a(e, `has unknown type '${s.type}'`);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
function A(e, t, s, r) {
|
|
161
|
-
if (typeof t != "number")
|
|
162
|
-
throw new a(e, `must be a number, got ${typeof t}`);
|
|
163
|
-
if (Number.isNaN(t))
|
|
164
|
-
throw new a(e, "must not be NaN");
|
|
165
|
-
if (!Number.isFinite(t))
|
|
166
|
-
throw new a(e, "must be finite");
|
|
167
|
-
if (r && !Number.isInteger(t))
|
|
168
|
-
throw new a(e, `must be an integer, got ${t}`);
|
|
169
|
-
if (s.min !== void 0 && t < s.min)
|
|
170
|
-
throw new a(e, `must be >= ${s.min}, got ${t}`);
|
|
171
|
-
if (s.max !== void 0 && t > s.max)
|
|
172
|
-
throw new a(e, `must be <= ${s.max}, got ${t}`);
|
|
173
|
-
}
|
|
174
|
-
function L(e, t, s) {
|
|
175
|
-
if (!s.options || s.options.length === 0)
|
|
176
|
-
throw new a(e, "is a select type but has no options defined");
|
|
177
|
-
if (!s.options.map((n) => n.value).includes(t)) {
|
|
178
|
-
const n = s.options.map((i) => `'${String(i.value)}'`).join(", ");
|
|
179
|
-
throw new a(e, `must be one of [${n}], got '${String(t)}'`);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
function P(e, t) {
|
|
183
|
-
const s = {};
|
|
184
|
-
for (const [r, n] of Object.entries(e)) {
|
|
185
|
-
const c = t?.[r] ?? n.default;
|
|
186
|
-
v(r, c, n), s[r] = c;
|
|
187
|
-
}
|
|
188
|
-
return s;
|
|
189
|
-
}
|
|
190
|
-
function ne(e) {
|
|
191
|
-
return e;
|
|
192
|
-
}
|
|
193
|
-
function x(e, t) {
|
|
194
|
-
const s = e.getSnapshot(), r = t === "directed" ? s : e.undirected(s).snapshot, n = r.flags.multigraph ? r.simplified({ weights: "sum" }).snapshot : r;
|
|
195
|
-
return B(n, t);
|
|
196
|
-
}
|
|
197
|
-
function oe(e) {
|
|
198
|
-
const t = e.getSnapshot();
|
|
199
|
-
return t.flags.multigraph ? t.edgeCount - t.simplified({ weights: "sum" }).snapshot.edgeCount : 0;
|
|
200
|
-
}
|
|
201
|
-
function B(e, t) {
|
|
202
|
-
const s = new _({
|
|
203
|
-
directed: t !== "undirected"
|
|
204
|
-
}), { ids: r } = e;
|
|
205
|
-
for (let o = 0; o < e.nodeCount; o++)
|
|
206
|
-
s.addNode(r.idOf(o));
|
|
207
|
-
const { src: n, dst: i, weights: c } = e.edgeList();
|
|
208
|
-
for (let o = 0; o < e.edgeCount; o++) {
|
|
209
|
-
const u = r.idOf(n[o]), h = r.idOf(i[o]), l = c === null ? 1 : c[o];
|
|
210
|
-
s.addEdge(u, h, l);
|
|
211
|
-
}
|
|
212
|
-
return s;
|
|
213
|
-
}
|
|
214
|
-
const m = /* @__PURE__ */ new Map();
|
|
215
|
-
function F(e, t) {
|
|
216
|
-
if (t === null)
|
|
217
|
-
return e;
|
|
218
|
-
if (e === null)
|
|
219
|
-
return t;
|
|
220
|
-
const s = new Uint32Array(e.length);
|
|
221
|
-
for (let r = 0; r < e.length; r++) {
|
|
222
|
-
const n = e[r];
|
|
223
|
-
s[r] = n === w ? w : t[n];
|
|
224
|
-
}
|
|
225
|
-
return s;
|
|
226
|
-
}
|
|
227
|
-
const O = class O {
|
|
228
|
-
/**
|
|
229
|
-
* Getter for schema options
|
|
230
|
-
*
|
|
231
|
-
* Algorithms that use the new schema-based options should access
|
|
232
|
-
* options via this getter.
|
|
233
|
-
* @returns The resolved schema options
|
|
234
|
-
*/
|
|
235
|
-
get schemaOptions() {
|
|
236
|
-
return this._schemaOptions;
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Creates a new algorithm instance
|
|
240
|
-
* @param g - The graph to run the algorithm on
|
|
241
|
-
* @param options - Optional configuration options (uses schema defaults if not provided)
|
|
242
|
-
*/
|
|
243
|
-
constructor(t, s) {
|
|
244
|
-
this.graph = t, this._schemaOptions = this.resolveOptions(s);
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* The `@graphty/algorithms` Graph this run reads, built from the element's graph snapshot.
|
|
248
|
-
*
|
|
249
|
-
* This is the ONLY way an algorithm should obtain its input. The `Node` and `Edge` objects the
|
|
250
|
-
* data manager also holds are render objects -- each `Node` builds a Babylon mesh in its
|
|
251
|
-
* constructor -- and reading the graph out of them ties every algorithm to a renderer and to
|
|
252
|
-
* whatever part of a data load the scene has caught up with.
|
|
253
|
-
* @param mode - the shape this algorithm needs; see {@link AlgorithmGraphMode}
|
|
254
|
-
* @returns a freshly built Graph for the algorithm package
|
|
255
|
-
*/
|
|
256
|
-
algorithmGraph(t) {
|
|
257
|
-
return x(this.graph.getDataManager(), t);
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* The route an algorithm with an accelerated implementation takes.
|
|
261
|
-
*
|
|
262
|
-
* It is the counterpart of {@link algorithmGraph} for the algorithms `@graphty/algorithms`
|
|
263
|
-
* can dispatch: instead of copying the snapshot into an object graph, the work runs over the
|
|
264
|
-
* snapshot itself, on the attached accelerator or on the index-based CPU port, and the adapter
|
|
265
|
-
* writes one loop over an index-aligned result either way.
|
|
266
|
-
*
|
|
267
|
-
* THE DECISION IS TAKEN ONCE, HERE, BEFORE ANY WORK STARTS. The controller answers "the policy
|
|
268
|
-
* is off", "no accelerator", "below `acceleration.minNodes`" or "this accelerator does not
|
|
269
|
-
* implement that" up front, and under `acceleration="required"` it throws `E_NO_ACCELERATOR`
|
|
270
|
-
* rather than answering quietly. After the work has started there is no second decision: a
|
|
271
|
-
* failure from the accelerator propagates with its code and fails the run, because a number
|
|
272
|
-
* that silently came from somewhere else is worse than no number.
|
|
273
|
-
* @param capability - The accelerator member this work would use, such as `"pageRank"`.
|
|
274
|
-
* @param mode - The shape this algorithm needs; see {@link AlgorithmGraphMode}. `"undirected"`
|
|
275
|
-
* takes the snapshot's undirected view, which is what collapses a reciprocal pair into one
|
|
276
|
-
* edge.
|
|
277
|
-
* @returns The snapshot, the edge map onto it, and the runner.
|
|
278
|
-
* @example
|
|
279
|
-
* ```ts
|
|
280
|
-
* const { snapshot, run } = this.accelerated("connectedComponents", "undirected");
|
|
281
|
-
* const { value, precision } = await run((dispatch, s) => dispatch.connectedComponents(s));
|
|
282
|
-
* const group = value.labels[snapshot.ids.indexOf(nodeId)];
|
|
283
|
-
* ```
|
|
284
|
-
*/
|
|
285
|
-
accelerated(t, s) {
|
|
286
|
-
const r = this.graph.getDataManager(), n = r.getSnapshot(), i = s === "undirected" ? r.undirected(n) : null, c = i === null ? n : i.snapshot, o = c.flags.multigraph ? c.simplified({ weights: "sum" }) : null, u = o === null ? c : o.snapshot, h = this.graph.acceleration, l = { capability: t, nodeCount: u.nodeCount };
|
|
287
|
-
return {
|
|
288
|
-
snapshot: u,
|
|
289
|
-
edgeRemap: F(i?.edgeRemap ?? null, o?.edgeRemap ?? null),
|
|
290
|
-
run: async (b) => {
|
|
291
|
-
const f = await h.run(
|
|
292
|
-
l,
|
|
293
|
-
(S) => b(y(R(S)), u)
|
|
294
|
-
);
|
|
295
|
-
return f.accelerated ? { value: f.value, precision: f.precision } : { value: await b(y(null), u), precision: M };
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* The dense row of a node the reader named in an option.
|
|
301
|
-
*
|
|
302
|
-
* A search takes its source as an id and the snapshot answers in indices, so this is where the
|
|
303
|
-
* two meet -- and where an id that names no node in the graph is reported as what it is: an
|
|
304
|
-
* option whose value is outside the permitted range, carrying the option's name and what was
|
|
305
|
-
* passed, rather than a silent empty result or a search from row zero.
|
|
306
|
-
* @param snapshot - The graph the work runs over.
|
|
307
|
-
* @param option - The option the id came from, named in the error.
|
|
308
|
-
* @param id - The node id the reader gave.
|
|
309
|
-
* @returns The node's dense row.
|
|
310
|
-
* @throws A `GraphtyError` with `E_OPTION_RANGE` when the graph has no such node.
|
|
311
|
-
*/
|
|
312
|
-
nodeIndex(t, s, r) {
|
|
313
|
-
const n = t.ids.indexOf(r);
|
|
314
|
-
if (n === w)
|
|
315
|
-
throw new d({
|
|
316
|
-
code: "E_OPTION_RANGE",
|
|
317
|
-
message: `the graph has no node "${String(r)}", so "${s}" names nothing to run from`,
|
|
318
|
-
source: "run",
|
|
319
|
-
details: { option: s, value: r }
|
|
320
|
-
});
|
|
321
|
-
return n;
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* Resolves and validates options against the schema
|
|
325
|
-
* @param options - User-provided options (partial)
|
|
326
|
-
* @returns Fully resolved options with defaults applied
|
|
327
|
-
*/
|
|
328
|
-
resolveOptions(t) {
|
|
329
|
-
const s = this.constructor.optionsSchema;
|
|
330
|
-
return Object.keys(s).length === 0 ? {} : P(s, t);
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* Gets the algorithm type
|
|
334
|
-
* @returns The algorithm type identifier
|
|
335
|
-
*/
|
|
336
|
-
get type() {
|
|
337
|
-
return this.constructor.type;
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* Gets the algorithm namespace
|
|
341
|
-
* @returns The algorithm namespace identifier
|
|
342
|
-
*/
|
|
343
|
-
get namespace() {
|
|
344
|
-
return this.constructor.namespace;
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Compute this algorithm and publish what it produced as a result object.
|
|
348
|
-
*
|
|
349
|
-
* This is the entry point the run machinery calls, and it is the one that makes an algorithm
|
|
350
|
-
* startable as a `Run`: it takes a signal it must throw from, a progress channel, a yield, and
|
|
351
|
-
* the run id the result is published under -- and it RETURNS the result rather than writing it
|
|
352
|
-
* somewhere a caller has to go looking for. `run()` is the 1.10 entry point beside it, which
|
|
353
|
-
* returns nothing and can be neither watched nor stopped.
|
|
354
|
-
*
|
|
355
|
-
* The default refuses, because an algorithm that has not been migrated genuinely cannot answer
|
|
356
|
-
* a run: it publishes through side effects under its own names and has no result object to
|
|
357
|
-
* hand back. Both shipped families -- a metric and a declared algorithm -- override it.
|
|
358
|
-
* @param _context - A signal, a progress channel and a yield.
|
|
359
|
-
* @param runId - The id the result is published under.
|
|
360
|
-
* @param _fields - The catalogue's descriptors for this algorithm's fields, when the caller
|
|
361
|
-
* holds them.
|
|
362
|
-
* @returns The result, or undefined when there was nothing to compute.
|
|
363
|
-
* @throws A `GraphtyError` with code `E_UNSUPPORTED` when this algorithm has no result to
|
|
364
|
-
* publish.
|
|
365
|
-
*/
|
|
366
|
-
publishResult(t, s, r) {
|
|
367
|
-
return Promise.reject(
|
|
368
|
-
new d({
|
|
369
|
-
code: "E_UNSUPPORTED",
|
|
370
|
-
message: `The "${this.namespace}:${this.type}" algorithm writes its result through side effects and cannot be started as a run.`,
|
|
371
|
-
source: "run",
|
|
372
|
-
target: { kind: "run", id: s },
|
|
373
|
-
details: { algorithm: `${this.namespace}:${this.type}` }
|
|
374
|
-
})
|
|
375
|
-
);
|
|
376
|
-
}
|
|
377
|
-
/**
|
|
378
|
-
* Registers an algorithm class in the global registry
|
|
379
|
-
* @param cls - The algorithm class to register
|
|
380
|
-
* @returns The registered algorithm class
|
|
381
|
-
*/
|
|
382
|
-
static register(t) {
|
|
383
|
-
const s = t, r = String(s.type), n = String(s.namespace), { descriptor: i, cost: c, version: o } = s;
|
|
384
|
-
return i !== void 0 && T({
|
|
385
|
-
descriptor: i,
|
|
386
|
-
namespace: n,
|
|
387
|
-
type: r,
|
|
388
|
-
...c === void 0 ? {} : { cost: c },
|
|
389
|
-
...o === void 0 ? {} : { version: o }
|
|
390
|
-
}), m.set(`${n}:${r}`, t), t;
|
|
391
|
-
}
|
|
392
|
-
/**
|
|
393
|
-
* Gets an algorithm instance from the registry
|
|
394
|
-
* @param g - The graph to run the algorithm on
|
|
395
|
-
* @param namespace - The algorithm namespace
|
|
396
|
-
* @param type - The algorithm type
|
|
397
|
-
* @param options - Optional algorithm-specific options to pass to constructor
|
|
398
|
-
* @returns A new instance of the algorithm, or null if not found
|
|
399
|
-
*/
|
|
400
|
-
static get(t, s, r, n) {
|
|
401
|
-
const i = m.get(`${s}:${r}`);
|
|
402
|
-
return i ? new i(t, n) : null;
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* Gets an algorithm class from the registry
|
|
406
|
-
* @param namespace - The algorithm namespace
|
|
407
|
-
* @param type - The algorithm type
|
|
408
|
-
* @returns The algorithm class, or null if not found
|
|
409
|
-
*/
|
|
410
|
-
static getClass(t, s) {
|
|
411
|
-
return m.get(`${t}:${s}`) ?? null;
|
|
412
|
-
}
|
|
413
|
-
/**
|
|
414
|
-
* Get the options schema for this algorithm
|
|
415
|
-
* @returns The options schema, or an empty object if no options defined
|
|
416
|
-
* @deprecated Use getZodOptionsSchema() instead
|
|
417
|
-
*/
|
|
418
|
-
static getOptionsSchema() {
|
|
419
|
-
return this.optionsSchema;
|
|
420
|
-
}
|
|
421
|
-
/**
|
|
422
|
-
* Check if this algorithm has configurable options
|
|
423
|
-
* @returns true if the algorithm has at least one option defined
|
|
424
|
-
* @deprecated Use hasZodOptions() instead
|
|
425
|
-
*/
|
|
426
|
-
static hasOptions() {
|
|
427
|
-
return Object.keys(this.optionsSchema).length > 0;
|
|
428
|
-
}
|
|
429
|
-
/**
|
|
430
|
-
* Get the Zod-based options schema for this algorithm.
|
|
431
|
-
* @returns The Zod options schema, or an empty object if no schema defined
|
|
432
|
-
*/
|
|
433
|
-
static getZodOptionsSchema() {
|
|
434
|
-
return this.zodOptionsSchema ?? {};
|
|
435
|
-
}
|
|
436
|
-
/**
|
|
437
|
-
* Check if this algorithm has a Zod-based options schema.
|
|
438
|
-
* @returns true if the algorithm has a Zod options schema defined
|
|
439
|
-
*/
|
|
440
|
-
static hasZodOptions() {
|
|
441
|
-
return this.zodOptionsSchema !== void 0 && Object.keys(this.zodOptionsSchema).length > 0;
|
|
442
|
-
}
|
|
443
|
-
/**
|
|
444
|
-
* Get all registered algorithm names.
|
|
445
|
-
* @param namespace - Optional namespace to filter by
|
|
446
|
-
* @returns Array of algorithm names in "namespace:type" format
|
|
447
|
-
*/
|
|
448
|
-
static getRegisteredAlgorithms(t) {
|
|
449
|
-
const s = [];
|
|
450
|
-
for (const r of m.keys())
|
|
451
|
-
(!t || r.startsWith(`${t}:`)) && s.push(r);
|
|
452
|
-
return s.sort();
|
|
453
|
-
}
|
|
454
|
-
/**
|
|
455
|
-
* Get all registered algorithm types.
|
|
456
|
-
* This method is provided for API consistency with DataSource.
|
|
457
|
-
* @returns Array of algorithm keys in "namespace:type" format
|
|
458
|
-
* @since 1.5.0
|
|
459
|
-
* @example
|
|
460
|
-
* ```typescript
|
|
461
|
-
* const types = Algorithm.getRegisteredTypes();
|
|
462
|
-
* console.log('Available algorithms:', types);
|
|
463
|
-
* // ['graphty:betweenness', 'graphty:closeness', 'graphty:degree', ...]
|
|
464
|
-
* ```
|
|
465
|
-
*/
|
|
466
|
-
static getRegisteredTypes() {
|
|
467
|
-
return this.getRegisteredAlgorithms();
|
|
468
|
-
}
|
|
469
|
-
};
|
|
470
|
-
O.optionsSchema = {};
|
|
471
|
-
let E = O;
|
|
472
|
-
export {
|
|
473
|
-
E as A,
|
|
474
|
-
M as C,
|
|
475
|
-
J as D,
|
|
476
|
-
a as O,
|
|
477
|
-
Y as a,
|
|
478
|
-
te as b,
|
|
479
|
-
re as c,
|
|
480
|
-
ne as d,
|
|
481
|
-
z as e,
|
|
482
|
-
P as f,
|
|
483
|
-
D as g,
|
|
484
|
-
Z as h,
|
|
485
|
-
X as i,
|
|
486
|
-
W as j,
|
|
487
|
-
ee as k,
|
|
488
|
-
Q as l,
|
|
489
|
-
se as m,
|
|
490
|
-
H as n,
|
|
491
|
-
oe as o,
|
|
492
|
-
K as r,
|
|
493
|
-
v
|
|
494
|
-
};
|