@graphty/graphty-element 2.5.1 → 2.6.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/dist/ai.js +3 -3
- package/dist/catalog.d.ts +16 -0
- package/dist/catalog.js +34 -32
- package/dist/chunks/{AiManager-CrbvKdEK.js → AiManager-4iQpsJW1.js} +4 -4
- package/dist/chunks/{DataSource-qU-nLhXN.js → DataSource-BL2UzPff.js} +2 -2
- package/dist/chunks/GraphSession-BhuHSXIo.js +12819 -0
- package/dist/chunks/{GraphtyLogger-DOTwCiMR.js → GraphtyLogger-B_O67a6c.js} +1 -1
- package/dist/chunks/{VoiceInputAdapter-D4NrRL_1.js → VoiceInputAdapter-Cc6mHXTI.js} +1 -1
- package/dist/chunks/{XRPivotCameraController-Uqa47vmo.js → XRPivotCameraController-BLa89LXn.js} +2 -2
- package/dist/chunks/{algorithms-D-ab-Auu.js → algorithms-BJ6DQMOe.js} +931 -781
- package/dist/chunks/{capability-check-Vw3IcqiE.js → capability-check-Am2zliFj.js} +1 -1
- package/dist/chunks/{detect-B4Qrw976.js → detect-fyuVnlCT.js} +1 -1
- package/dist/chunks/{format-detection-r2IfNFXO.js → format-detection-BHwrAVzW.js} +1 -1
- package/dist/chunks/{index-J9MgLio9.js → index-BkBLbvui.js} +2691 -2434
- package/dist/chunks/optionsFromZod-CKMYSwTz.js +3636 -0
- package/dist/chunks/{paletteRegistry-Kt-6CeoN.js → paletteRegistry-BCFSwJGK.js} +224 -189
- package/dist/chunks/parse-BMTqt4SS.js +3658 -0
- package/dist/chunks/{types-C_c53VgR.js → types-DFchv4Ny.js} +4 -1
- package/dist/custom-elements.json +1 -1
- package/dist/extend.d.ts +10 -8
- package/dist/extend.js +6 -6
- package/dist/graphty-catalog.json +75 -38
- package/dist/graphty.bundle.js +55368 -48970
- package/dist/graphty.js +19 -19
- package/dist/index.d.ts +1 -1
- package/dist/logging.js +2 -2
- package/dist/schema.d.ts +15 -1
- package/dist/schema.js +1 -1
- package/dist/session.d.ts +30 -7
- package/dist/session.js +40 -37
- package/dist/src/Graph.d.ts +35 -7
- package/dist/src/acceleration/types.d.ts +79 -43
- package/dist/src/algorithms/Algorithm.d.ts +52 -4
- package/dist/src/algorithms/BFSAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/BellmanFordAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/BetweennessCentralityAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/BipartiteMatchingAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/ClosenessCentralityAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/ConnectedComponentsAlgorithm.d.ts +4 -1
- package/dist/src/algorithms/DFSAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/DegreeAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/DijkstraAlgorithm.d.ts +6 -0
- package/dist/src/algorithms/EigenvectorCentralityAlgorithm.d.ts +2 -0
- package/dist/src/algorithms/FloydWarshallAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/GirvanNewmanAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/HITSAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/KCoreAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/KatzCentralityAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/KruskalAlgorithm.d.ts +4 -1
- package/dist/src/algorithms/LabelPropagationAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/LeidenAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/LinkPredictionAlgorithm.d.ts +4 -1
- package/dist/src/algorithms/LouvainAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/MaxFlowAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/MinCutAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/PageRankAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/PrimAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/StronglyConnectedComponentsAlgorithm.d.ts +3 -0
- package/dist/src/algorithms/input/ScopedInput.d.ts +185 -0
- package/dist/src/algorithms/input/derivedInputs.d.ts +199 -0
- package/dist/src/algorithms/input/maskBack.d.ts +37 -0
- package/dist/src/algorithms/metrics/MetricAlgorithm.d.ts +3 -3
- package/dist/src/algorithms/results/DeclaredAlgorithm.d.ts +4 -3
- package/dist/src/algorithms/results/types.d.ts +28 -6
- package/dist/src/algorithms/utils/communityUtils.d.ts +0 -48
- package/dist/src/algorithms/utils/graphUtils.d.ts +2 -68
- package/dist/src/algorithms/utils/snapshotGraph.d.ts +3 -1
- package/dist/src/catalog/algorithms.d.ts +3 -0
- package/dist/src/catalog/layouts.d.ts +2 -0
- package/dist/src/catalog/sets/canonical.d.ts +68 -0
- package/dist/src/catalog/sets/hash.d.ts +126 -0
- package/dist/src/catalog/sets/parse.d.ts +115 -0
- package/dist/src/catalog/types.d.ts +329 -8
- package/dist/src/data/GraphStore.d.ts +73 -1
- package/dist/src/data/edgeIdentity.d.ts +202 -1
- package/dist/src/data/ingest.d.ts +3 -1
- package/dist/src/data/report.d.ts +20 -0
- package/dist/src/graphty-element.d.ts +42 -6
- package/dist/src/layout/D3GraphLayoutEngine.d.ts +11 -0
- package/dist/src/layout/LayoutEngine.d.ts +56 -0
- package/dist/src/layout/NGraphLayoutEngine.d.ts +10 -0
- package/dist/src/layout/SimulationLayoutEngine.d.ts +11 -0
- package/dist/src/managers/AlgorithmManager.d.ts +8 -0
- package/dist/src/managers/DataManager.d.ts +11 -0
- package/dist/src/managers/LayoutManager.d.ts +126 -2
- package/dist/src/managers/StatsManager.d.ts +1 -0
- package/dist/src/session/GraphSession.d.ts +48 -0
- package/dist/src/session/attributes.d.ts +121 -1
- package/dist/src/session/cost/estimate.d.ts +20 -0
- package/dist/src/session/cost/index.d.ts +1 -1
- package/dist/src/session/planning.d.ts +32 -2
- package/dist/src/session/query.d.ts +7 -0
- package/dist/src/session/results/ResultsApi.d.ts +14 -1
- package/dist/src/session/runs/Run.d.ts +65 -4
- package/dist/src/session/runs/RunsApi.d.ts +58 -2
- package/dist/src/session/runs/runId.d.ts +55 -6
- package/dist/src/session/runs/types.d.ts +36 -8
- package/dist/src/session/scope/ElementMask.d.ts +14 -1
- package/dist/src/session/scope/ScopeApi.d.ts +160 -31
- package/dist/src/session/scope/index.d.ts +1 -1
- package/dist/src/session/selection/SelectionApi.d.ts +15 -10
- package/dist/src/session/selection/index.d.ts +1 -1
- package/dist/src/session/selection/targets.d.ts +6 -7
- package/dist/src/session/sets/SetsApi.d.ts +110 -0
- package/dist/src/session/sets/algebra.d.ts +124 -0
- package/dist/src/session/sets/cache.d.ts +197 -0
- package/dist/src/session/sets/captures.d.ts +83 -0
- package/dist/src/session/sets/dependencies.d.ts +167 -0
- package/dist/src/session/sets/layers.d.ts +101 -0
- package/dist/src/session/sets/notify.d.ts +122 -0
- package/dist/src/session/sets/offers.d.ts +103 -0
- package/dist/src/session/sets/path.d.ts +37 -0
- package/dist/src/session/sets/prepare.d.ts +209 -0
- package/dist/src/session/sets/resolve.d.ts +311 -0
- package/dist/src/session/sets/signature.d.ts +77 -0
- package/dist/src/session/sets/status.d.ts +98 -0
- package/dist/src/session/sets/store.d.ts +196 -0
- package/dist/src/session/sets/types.d.ts +386 -0
- package/dist/src/session/styles/Layer.d.ts +9 -2
- package/dist/src/session/styles/StylesApi.d.ts +5 -2
- package/dist/src/session/styles/explain.d.ts +5 -2
- package/dist/src/session/styles/predicate.d.ts +41 -2
- package/dist/src/session/styles/repaint.d.ts +19 -0
- package/dist/src/session/styles/selector.d.ts +16 -5
- package/dist/src/session/types.d.ts +18 -0
- package/dist/src/session/visibility/VisibilityApi.d.ts +47 -3
- package/dist/src/session/visibility/filter.d.ts +86 -51
- package/dist/src/session/visibility/index.d.ts +1 -1
- package/dist/src/testing/fakeAccelerator.d.ts +5 -0
- package/dist/src/utils/queue-migration.d.ts +17 -0
- package/package.json +15 -9
- package/dist/chunks/GraphSession-DuAhRgCd.js +0 -8622
- package/dist/chunks/optionsFromZod-B9RncoTX.js +0 -2578
- package/dist/chunks/scales-CJCRwi2J.js +0 -3220
- package/dist/src/algorithms/utils/index.d.ts +0 -6
|
@@ -0,0 +1,3636 @@
|
|
|
1
|
+
import { c as yt, G as g, S as Zt } from "./pluginRegistry-Bs8bEkz9.js";
|
|
2
|
+
import { K as Xt, f as Qt } from "./types-DFchv4Ny.js";
|
|
3
|
+
import { b as en } from "./GraphtyLogger-B_O67a6c.js";
|
|
4
|
+
import { Graph as tn, accelerated as Je } from "@graphty/algorithms";
|
|
5
|
+
import { INVALID_INDEX as E, maskTest as oe, makeMask as he } from "@graphty/graph-format";
|
|
6
|
+
import { z as bt } from "zod/v4";
|
|
7
|
+
const ie = yt({
|
|
8
|
+
kind: "camera",
|
|
9
|
+
idOf: (e) => e.descriptor.id,
|
|
10
|
+
descriptorOf: (e) => e.descriptor,
|
|
11
|
+
implementationOf: (e) => e.compute,
|
|
12
|
+
builtInIds: () => Xt
|
|
13
|
+
});
|
|
14
|
+
function ks(e, t) {
|
|
15
|
+
const n = e.descriptor;
|
|
16
|
+
if (n === void 0 || typeof n != "object")
|
|
17
|
+
throw new g({
|
|
18
|
+
code: "E_BAD_COMMAND",
|
|
19
|
+
message: "registerCameraView takes a camera view with a descriptor",
|
|
20
|
+
source: "registry",
|
|
21
|
+
details: { kind: "camera", field: "descriptor" }
|
|
22
|
+
});
|
|
23
|
+
if (!Array.isArray(n.modes) || n.modes.length === 0)
|
|
24
|
+
throw new g({
|
|
25
|
+
code: "E_BAD_COMMAND",
|
|
26
|
+
message: `the camera view "${String(n.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`,
|
|
27
|
+
source: "registry",
|
|
28
|
+
details: { kind: "camera", name: String(n.id), field: "modes" }
|
|
29
|
+
});
|
|
30
|
+
if (!Array.isArray(n.options))
|
|
31
|
+
throw new g({
|
|
32
|
+
code: "E_BAD_COMMAND",
|
|
33
|
+
message: `the camera view "${String(n.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`,
|
|
34
|
+
source: "registry",
|
|
35
|
+
details: { kind: "camera", name: String(n.id), field: "options" }
|
|
36
|
+
});
|
|
37
|
+
if (typeof e.compute != "function")
|
|
38
|
+
throw new g({
|
|
39
|
+
code: "E_BAD_COMMAND",
|
|
40
|
+
message: `the camera view "${String(n.id)}" was registered without a compute function`,
|
|
41
|
+
source: "registry",
|
|
42
|
+
details: { kind: "camera", name: String(n.id), field: "compute" }
|
|
43
|
+
});
|
|
44
|
+
ie.register(e, t);
|
|
45
|
+
}
|
|
46
|
+
function As() {
|
|
47
|
+
return ie.descriptors();
|
|
48
|
+
}
|
|
49
|
+
function Ss(e) {
|
|
50
|
+
return ie.byId(e);
|
|
51
|
+
}
|
|
52
|
+
function Ns() {
|
|
53
|
+
ie.clearForTesting();
|
|
54
|
+
}
|
|
55
|
+
const nn = ["forceAtlas2", "fruchtermanReingold", "springElectrical", "release"], rn = [
|
|
56
|
+
"pageRank",
|
|
57
|
+
"sssp",
|
|
58
|
+
"breadthFirstSearch",
|
|
59
|
+
"connectedComponents",
|
|
60
|
+
"weaklyConnectedComponents",
|
|
61
|
+
"minimumSpanningTree"
|
|
62
|
+
];
|
|
63
|
+
function Es(e) {
|
|
64
|
+
const t = {
|
|
65
|
+
kind: e.backend
|
|
66
|
+
};
|
|
67
|
+
for (const n of nn) {
|
|
68
|
+
const r = e[n];
|
|
69
|
+
typeof r == "function" && (t[n] = r.bind(e));
|
|
70
|
+
}
|
|
71
|
+
return t;
|
|
72
|
+
}
|
|
73
|
+
function sn(e) {
|
|
74
|
+
const t = {
|
|
75
|
+
kind: e.backend
|
|
76
|
+
};
|
|
77
|
+
for (const n of rn) {
|
|
78
|
+
const r = e[n];
|
|
79
|
+
typeof r == "function" && (t[n] = r.bind(e));
|
|
80
|
+
}
|
|
81
|
+
return t;
|
|
82
|
+
}
|
|
83
|
+
const on = ["auto", "off", "required"], Is = "auto";
|
|
84
|
+
function Rs(e) {
|
|
85
|
+
return typeof e == "string" && on.includes(e);
|
|
86
|
+
}
|
|
87
|
+
const an = "f64", Ms = "f32", $s = "acceleration.minNodes", Cs = 0, _s = "RTX 4070 SUPER, headless Chromium, 2026-09-27", Ts = Object.freeze(
|
|
88
|
+
{
|
|
89
|
+
// Above the 50,000-node render ceiling, so not routed to the device today; the kernel's own
|
|
90
|
+
// resident crossover, because the element cannot hold a graph this large to measure one.
|
|
91
|
+
breadthFirstSearch: 141e3,
|
|
92
|
+
// Likewise above the render ceiling, and likewise the kernel's resident crossover.
|
|
93
|
+
sssp: 107e3,
|
|
94
|
+
// Measured through the element: the only capability that crosses inside what it can hold.
|
|
95
|
+
pageRank: 5e4,
|
|
96
|
+
// Above the render ceiling. Was 50,000, where the device measured 0.51x -- twice as slow.
|
|
97
|
+
connectedComponents: 132e3
|
|
98
|
+
}
|
|
99
|
+
), ae = yt({
|
|
100
|
+
kind: "algorithm",
|
|
101
|
+
idOf: (e) => e.descriptor.key,
|
|
102
|
+
descriptorOf: (e) => e.descriptor,
|
|
103
|
+
implementationOf: (e) => e.descriptor,
|
|
104
|
+
builtInIds: () => Qt
|
|
105
|
+
});
|
|
106
|
+
function cn(e, t) {
|
|
107
|
+
if (e.descriptor.key !== e.type)
|
|
108
|
+
throw new g({
|
|
109
|
+
code: "E_BAD_COMMAND",
|
|
110
|
+
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".`,
|
|
111
|
+
source: "registry",
|
|
112
|
+
details: {
|
|
113
|
+
kind: "algorithm",
|
|
114
|
+
field: "descriptor.key",
|
|
115
|
+
key: e.descriptor.key,
|
|
116
|
+
type: e.type,
|
|
117
|
+
namespace: e.namespace
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
if (e.descriptor.fields.find((r) => r.name === "runs") !== void 0)
|
|
121
|
+
throw new g({
|
|
122
|
+
code: "E_BAD_COMMAND",
|
|
123
|
+
message: `the algorithm "${e.namespace}:${e.type}" publishes a field named "runs", which is reserved. Name the field something else.`,
|
|
124
|
+
source: "registry",
|
|
125
|
+
details: { kind: "algorithm", field: "descriptor.fields", name: "runs", reason: "reserved-field" }
|
|
126
|
+
});
|
|
127
|
+
ae.register(e, t);
|
|
128
|
+
}
|
|
129
|
+
function Fs() {
|
|
130
|
+
return ae.descriptors();
|
|
131
|
+
}
|
|
132
|
+
function xs(e) {
|
|
133
|
+
return ae.byId(e);
|
|
134
|
+
}
|
|
135
|
+
function zs() {
|
|
136
|
+
ae.clearForTesting();
|
|
137
|
+
}
|
|
138
|
+
const un = {
|
|
139
|
+
fixed: ["kind", "nodes", "edges", "reading"],
|
|
140
|
+
rule: ["kind", "where", "reading"],
|
|
141
|
+
path: ["kind", "nodes", "edges", "directed"]
|
|
142
|
+
}, wt = ["source", "target", "id", "key", "ordinal", "among"];
|
|
143
|
+
function S(e) {
|
|
144
|
+
const t = {};
|
|
145
|
+
for (const n of Object.keys(e).sort())
|
|
146
|
+
e[n] !== void 0 && (t[n] = e[n]);
|
|
147
|
+
return t;
|
|
148
|
+
}
|
|
149
|
+
function R(e) {
|
|
150
|
+
return e === 0 ? 0 : e;
|
|
151
|
+
}
|
|
152
|
+
function vt(e, t) {
|
|
153
|
+
return e === t ? 0 : e < t ? -1 : 1;
|
|
154
|
+
}
|
|
155
|
+
function z(e, t) {
|
|
156
|
+
return typeof e == "number" ? typeof t == "number" ? e - t : -1 : typeof t == "number" ? 1 : vt(String(e), String(t));
|
|
157
|
+
}
|
|
158
|
+
function Ot(e, t) {
|
|
159
|
+
for (const n of wt) {
|
|
160
|
+
const r = e[n], s = t[n];
|
|
161
|
+
if (r === void 0 || s === void 0) {
|
|
162
|
+
if (r !== s)
|
|
163
|
+
return r === void 0 ? -1 : 1;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const o = z(r, s);
|
|
167
|
+
if (o !== 0)
|
|
168
|
+
return o;
|
|
169
|
+
}
|
|
170
|
+
return vt(JSON.stringify(e), JSON.stringify(t));
|
|
171
|
+
}
|
|
172
|
+
function U(e, t) {
|
|
173
|
+
const n = [...e].sort(t);
|
|
174
|
+
return n.filter((r, s) => s === 0 || t(n[s - 1], r) !== 0);
|
|
175
|
+
}
|
|
176
|
+
function Ls(e) {
|
|
177
|
+
return U(e, (t, n) => Ot(t, n));
|
|
178
|
+
}
|
|
179
|
+
function js(e) {
|
|
180
|
+
return U(e.map(R), z);
|
|
181
|
+
}
|
|
182
|
+
function _e(e) {
|
|
183
|
+
const t = e, n = { ...t };
|
|
184
|
+
for (const r of wt)
|
|
185
|
+
n[r] = R(t[r]);
|
|
186
|
+
return S(n);
|
|
187
|
+
}
|
|
188
|
+
function kt(e) {
|
|
189
|
+
return U(
|
|
190
|
+
e.map(_e),
|
|
191
|
+
(t, n) => Ot(t, n)
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
function dn(e) {
|
|
195
|
+
return e === void 0 || e.length === 0 ? void 0 : kt(e);
|
|
196
|
+
}
|
|
197
|
+
function ln(e) {
|
|
198
|
+
if (e === null)
|
|
199
|
+
return null;
|
|
200
|
+
if (!Array.isArray(e))
|
|
201
|
+
return _e(e);
|
|
202
|
+
const t = kt(e);
|
|
203
|
+
return t.length === 1 ? t[0] : t;
|
|
204
|
+
}
|
|
205
|
+
const fn = /* @__PURE__ */ new Set([
|
|
206
|
+
"expression",
|
|
207
|
+
"edges",
|
|
208
|
+
"range",
|
|
209
|
+
"categories",
|
|
210
|
+
"degree",
|
|
211
|
+
"component",
|
|
212
|
+
"neighborhood",
|
|
213
|
+
"threshold"
|
|
214
|
+
]);
|
|
215
|
+
function pn(e) {
|
|
216
|
+
if (typeof e != "object" || e === null)
|
|
217
|
+
return e;
|
|
218
|
+
const t = e;
|
|
219
|
+
return typeof t.runId == "string" ? t.runId : typeof t.id == "string" ? t.id : e;
|
|
220
|
+
}
|
|
221
|
+
function hn(e) {
|
|
222
|
+
if (typeof e != "object" || e === null || Array.isArray(e))
|
|
223
|
+
return e;
|
|
224
|
+
const t = e, { key: n } = t, r = typeof n == "object" && n !== null && !Array.isArray(n) ? S({ ...n, value: R(n.value) }) : n;
|
|
225
|
+
return S({ ...t, result: pn(t.result), key: r });
|
|
226
|
+
}
|
|
227
|
+
function ge(e) {
|
|
228
|
+
if (typeof e != "object" || e === null || Array.isArray(e))
|
|
229
|
+
return e;
|
|
230
|
+
const t = e, { kind: n } = t;
|
|
231
|
+
if (n === "all" || n === "any")
|
|
232
|
+
return S({ ...t, of: Array.isArray(t.of) ? t.of.map(ge) : t.of });
|
|
233
|
+
if (n === "not")
|
|
234
|
+
return S({ ...t, of: ge(t.of) });
|
|
235
|
+
if (n === "member")
|
|
236
|
+
return S({ ...t, of: gn(t.of) });
|
|
237
|
+
if (n === "item")
|
|
238
|
+
return S({ ...t, item: hn(t.item) });
|
|
239
|
+
if (typeof n == "string" && fn.has(n)) {
|
|
240
|
+
const r = {};
|
|
241
|
+
for (const [s, o] of Object.entries(t))
|
|
242
|
+
r[s] = s === "seeds" && Array.isArray(o) ? o.map(R) : R(o);
|
|
243
|
+
return S(r);
|
|
244
|
+
}
|
|
245
|
+
return e;
|
|
246
|
+
}
|
|
247
|
+
function gn(e) {
|
|
248
|
+
if (typeof e != "object" || e === null || Array.isArray(e))
|
|
249
|
+
return e;
|
|
250
|
+
const t = e;
|
|
251
|
+
return q(t, ["define"]) && q(t, ["nodes"]) ? e : typeof t.define == "object" && t.define !== null ? { define: At(t.define) } : Array.isArray(t.nodes) ? { nodes: U(t.nodes.map(R), z) } : e;
|
|
252
|
+
}
|
|
253
|
+
function q(e, t) {
|
|
254
|
+
return Object.keys(e).some((n) => e[n] !== void 0 && !t.includes(n));
|
|
255
|
+
}
|
|
256
|
+
function At(e) {
|
|
257
|
+
const t = e;
|
|
258
|
+
switch (e.kind) {
|
|
259
|
+
case "fixed": {
|
|
260
|
+
const n = q(t, un.fixed), { reading: r, edges: s } = e, o = e.nodes.map(R);
|
|
261
|
+
return S({
|
|
262
|
+
...t,
|
|
263
|
+
nodes: n ? o : U(o, z),
|
|
264
|
+
edges: n ? s?.map(_e) : dn(s),
|
|
265
|
+
reading: r === "clipped" ? "listed" : r
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
case "rule": {
|
|
269
|
+
const n = ge(e.where), r = typeof n == "object" && n.kind === "expression" && !q(n, ["kind", "where"]) ? n.where : n;
|
|
270
|
+
return S({ ...t, where: r });
|
|
271
|
+
}
|
|
272
|
+
case "path": {
|
|
273
|
+
const n = e.edges?.map(ln);
|
|
274
|
+
return S({
|
|
275
|
+
...t,
|
|
276
|
+
nodes: e.nodes.map(R),
|
|
277
|
+
edges: n === void 0 || n.length === 0 ? void 0 : n,
|
|
278
|
+
directed: e.directed === !1 ? void 0 : e.directed
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
default:
|
|
282
|
+
return e;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const me = { a: 0, b: 0 }, Te = 2166136261, K = 16777619, Fe = 461845907, Z = 2246822507, ye = 35, mn = 36, St = 105, yn = 107, Nt = 111, X = new DataView(new ArrayBuffer(8)), Et = new Float64Array(X.buffer), It = new Uint32Array(X.buffer), D = new Float64Array(4), Rt = new Uint8Array(new Uint32Array([1]).buffer)[0] === 1;
|
|
286
|
+
let F = Te, x = Fe;
|
|
287
|
+
function M() {
|
|
288
|
+
F = Te, x = Fe;
|
|
289
|
+
}
|
|
290
|
+
function I(e) {
|
|
291
|
+
F = Math.imul(F ^ e, K) >>> 0, x = Math.imul(x ^ e, Z) >>> 0;
|
|
292
|
+
}
|
|
293
|
+
function b(e) {
|
|
294
|
+
if (I(ye), !Rt) {
|
|
295
|
+
X.setFloat64(0, e === 0 ? 0 : e, !0);
|
|
296
|
+
for (let r = 0; r < 8; r++)
|
|
297
|
+
I(X.getUint8(r));
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
Et[0] = e === 0 ? 0 : e;
|
|
301
|
+
let t = F, n = x;
|
|
302
|
+
for (let r = 0; r < 2; r++) {
|
|
303
|
+
const s = It[r];
|
|
304
|
+
for (let o = 0; o < 32; o += 8) {
|
|
305
|
+
const i = s >>> o & 255;
|
|
306
|
+
t = Math.imul(t ^ i, K) >>> 0, n = Math.imul(n ^ i, Z) >>> 0;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
F = t, x = n;
|
|
310
|
+
}
|
|
311
|
+
function xe(e) {
|
|
312
|
+
I(mn);
|
|
313
|
+
for (let t = 0; t < e.length; t++)
|
|
314
|
+
I(e.charCodeAt(t));
|
|
315
|
+
}
|
|
316
|
+
function Q(e) {
|
|
317
|
+
typeof e == "number" ? b(e) : xe(e);
|
|
318
|
+
}
|
|
319
|
+
function ee(e) {
|
|
320
|
+
let t = e ^ e >>> 16;
|
|
321
|
+
return t = Math.imul(t, 2246822507), t ^= t >>> 13, t = Math.imul(t, 3266489909), (t ^ t >>> 16) >>> 0;
|
|
322
|
+
}
|
|
323
|
+
function $() {
|
|
324
|
+
return { a: ee(F), b: ee(x) };
|
|
325
|
+
}
|
|
326
|
+
function be(e) {
|
|
327
|
+
return M(), Q(e), $();
|
|
328
|
+
}
|
|
329
|
+
function te(e, t) {
|
|
330
|
+
if (!Rt)
|
|
331
|
+
return M(), b(e.a), b(e.b), b(t.a), b(t.b), $();
|
|
332
|
+
let n = Te, r = Fe;
|
|
333
|
+
D[0] = e.a, D[1] = e.b, D[2] = t.a, D[3] = t.b;
|
|
334
|
+
for (let s = 0; s < 4; s++) {
|
|
335
|
+
Et[0] = D[s], n = Math.imul(n ^ ye, K) >>> 0, r = Math.imul(r ^ ye, Z) >>> 0;
|
|
336
|
+
for (let o = 0; o < 2; o++) {
|
|
337
|
+
const i = It[o];
|
|
338
|
+
for (let a = 0; a < 32; a += 8) {
|
|
339
|
+
const c = i >>> a & 255;
|
|
340
|
+
n = Math.imul(n ^ c, K) >>> 0, r = Math.imul(r ^ c, Z) >>> 0;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return { a: ee(n), b: ee(r) };
|
|
345
|
+
}
|
|
346
|
+
function bn(e) {
|
|
347
|
+
if (M(), e.id !== void 0)
|
|
348
|
+
I(St), Q(e.id);
|
|
349
|
+
else if (e.key !== void 0)
|
|
350
|
+
I(yn), Q(e.key);
|
|
351
|
+
else if (e.ordinal !== void 0 && e.among !== void 0)
|
|
352
|
+
I(Nt), b(e.ordinal), b(e.among);
|
|
353
|
+
else
|
|
354
|
+
throw new Error("an edge member needs an id, a key, or an ordinal with among");
|
|
355
|
+
return $();
|
|
356
|
+
}
|
|
357
|
+
function ze(e) {
|
|
358
|
+
return be(e);
|
|
359
|
+
}
|
|
360
|
+
function Mt(e, t) {
|
|
361
|
+
const n = be(e.source), r = be(e.target), s = t ? te(n, r) : we(n, r);
|
|
362
|
+
return te(s, bn(e));
|
|
363
|
+
}
|
|
364
|
+
function wn(e, t, n, r, s, o) {
|
|
365
|
+
const i = n ? te(e, t) : { a: e.a + t.a >>> 0, b: e.b + t.b >>> 0 };
|
|
366
|
+
let a;
|
|
367
|
+
return r !== void 0 ? (M(), I(St), Q(r), a = $()) : ((s !== We || o !== Ye) && (M(), I(Nt), b(s), b(o), We = s, Ye = o, qe = $()), a = qe), te(i, a);
|
|
368
|
+
}
|
|
369
|
+
let We = -1, Ye = -1, qe = me;
|
|
370
|
+
function we(e, t) {
|
|
371
|
+
return { a: e.a + t.a >>> 0, b: e.b + t.b >>> 0 };
|
|
372
|
+
}
|
|
373
|
+
function Ds(e, t) {
|
|
374
|
+
return { a: e.a - t.a >>> 0, b: e.b - t.b >>> 0 };
|
|
375
|
+
}
|
|
376
|
+
function ce(e) {
|
|
377
|
+
return e.a.toString(16).padStart(8, "0") + e.b.toString(16).padStart(8, "0");
|
|
378
|
+
}
|
|
379
|
+
function ne(e, t) {
|
|
380
|
+
return { count: e, sum: ce(t) };
|
|
381
|
+
}
|
|
382
|
+
function Ps(e, t, n) {
|
|
383
|
+
const r = {
|
|
384
|
+
...n === void 0 || n.count === 0 ? {} : { edges: ne(n.count, n.sum) },
|
|
385
|
+
kind: "fixed",
|
|
386
|
+
nodes: ne(t.count, t.sum),
|
|
387
|
+
reading: e
|
|
388
|
+
};
|
|
389
|
+
return M(), xe(JSON.stringify(r)), `r1:${ce($())}`;
|
|
390
|
+
}
|
|
391
|
+
function Hs(e) {
|
|
392
|
+
const t = At(e);
|
|
393
|
+
let n = t;
|
|
394
|
+
if (t.kind === "fixed") {
|
|
395
|
+
let r = me;
|
|
396
|
+
for (const o of t.nodes)
|
|
397
|
+
r = we(r, ze(o));
|
|
398
|
+
const s = { ...t, nodes: ne(t.nodes.length, r) };
|
|
399
|
+
if (t.edges !== void 0) {
|
|
400
|
+
let o = me;
|
|
401
|
+
for (const i of t.edges)
|
|
402
|
+
o = we(o, Mt(i, !0));
|
|
403
|
+
s.edges = ne(t.edges.length, o);
|
|
404
|
+
}
|
|
405
|
+
n = s;
|
|
406
|
+
}
|
|
407
|
+
return M(), xe(JSON.stringify(n)), `r1:${ce($())}`;
|
|
408
|
+
}
|
|
409
|
+
function Us(e, t) {
|
|
410
|
+
return M(), b(e.count), b(e.sum.a), b(e.sum.b), b(t.count), b(t.sum.a), b(t.sum.b), `d1:${ce($())}`;
|
|
411
|
+
}
|
|
412
|
+
function vn(e) {
|
|
413
|
+
return String(e);
|
|
414
|
+
}
|
|
415
|
+
function On(e) {
|
|
416
|
+
if (!/^\d+$/.test(e))
|
|
417
|
+
return E;
|
|
418
|
+
const t = Number(e);
|
|
419
|
+
return Number.isSafeInteger(t) ? t : E;
|
|
420
|
+
}
|
|
421
|
+
function kn(e, t) {
|
|
422
|
+
const n = On(t);
|
|
423
|
+
return n === E ? E : e.edgeIndexOf(n);
|
|
424
|
+
}
|
|
425
|
+
function Gs() {
|
|
426
|
+
return { next: 0 };
|
|
427
|
+
}
|
|
428
|
+
function $t(e) {
|
|
429
|
+
return `graphty:e${e}`;
|
|
430
|
+
}
|
|
431
|
+
function Bs(e, t, n) {
|
|
432
|
+
switch (e) {
|
|
433
|
+
case "keep":
|
|
434
|
+
return { kind: "add" };
|
|
435
|
+
case "error":
|
|
436
|
+
return { kind: "refuse" };
|
|
437
|
+
case "first":
|
|
438
|
+
return { kind: "drop" };
|
|
439
|
+
case "sum":
|
|
440
|
+
return { kind: "merge", weight: t + n, replaceRecord: !1 };
|
|
441
|
+
case "min":
|
|
442
|
+
return { kind: "merge", weight: Math.min(t, n), replaceRecord: !1 };
|
|
443
|
+
case "max":
|
|
444
|
+
return { kind: "merge", weight: Math.max(t, n), replaceRecord: !1 };
|
|
445
|
+
default:
|
|
446
|
+
return { kind: "merge", weight: n, replaceRecord: !0 };
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
const ve = "graphty.edgeId", B = {
|
|
450
|
+
/** Node: `hashNodeId` of the node id, two uint32 lanes. */
|
|
451
|
+
nodeHash: "graphty.nodeHash",
|
|
452
|
+
/** Edge: `hashEdgeMember` of the edge's stable identity, two uint32 lanes. */
|
|
453
|
+
edgeHash: "graphty.edgeHash",
|
|
454
|
+
/** Edge: its position among its pair's surviving edges in its load; -1 for a session edge. */
|
|
455
|
+
edgeOrdinal: "graphty.edgeOrdinal",
|
|
456
|
+
/** Edge: its pair's surviving edge count in its load; -1 for a session edge. */
|
|
457
|
+
edgeAmong: "graphty.edgeAmong"
|
|
458
|
+
}, An = "graphty.edgePairsOrdered";
|
|
459
|
+
function Sn(e, t, n, r, s) {
|
|
460
|
+
const o = e.length, i = new Uint32Array(o), a = new Uint32Array(o);
|
|
461
|
+
let c = 0;
|
|
462
|
+
for (let h = 0; h < o; h++) {
|
|
463
|
+
const [A, L] = t.endpoints(e[h]), j = !n && L < A;
|
|
464
|
+
i[h] = j ? L : A, a[h] = j ? A : L, c = Math.max(c, i[h] + 1, a[h] + 1);
|
|
465
|
+
}
|
|
466
|
+
const { perm: u, bytes: f } = Nn(i, a, c);
|
|
467
|
+
e.byteLength + i.byteLength + a.byteLength + f;
|
|
468
|
+
const l = t.hashOf === void 0 ? (h) => ze(t.idOf(h)) : t.hashOf.bind(t);
|
|
469
|
+
let d = 0, p = -1, w = { a: 0, b: 0 };
|
|
470
|
+
for (; d < o; ) {
|
|
471
|
+
const h = u[d];
|
|
472
|
+
let A = d + 1;
|
|
473
|
+
for (; A < o && i[u[A]] === i[h] && a[u[A]] === a[h]; )
|
|
474
|
+
A++;
|
|
475
|
+
i[h] !== p && (p = i[h], w = l(p));
|
|
476
|
+
const L = l(a[h]), j = A - d;
|
|
477
|
+
for (let G = d; G < A; G++) {
|
|
478
|
+
const Be = u[G], Ve = G - d;
|
|
479
|
+
s(
|
|
480
|
+
e[Be],
|
|
481
|
+
Ve,
|
|
482
|
+
j,
|
|
483
|
+
wn(w, L, n, r(Be), Ve, j)
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
d = A;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
function Nn(e, t, n) {
|
|
490
|
+
const r = e.length;
|
|
491
|
+
if (n > 4 * r) {
|
|
492
|
+
const c = new Uint32Array(r);
|
|
493
|
+
for (let u = 0; u < r; u++)
|
|
494
|
+
c[u] = u;
|
|
495
|
+
return c.sort((u, f) => e[u] - e[f] || t[u] - t[f] || u - f), { perm: c, bytes: c.byteLength };
|
|
496
|
+
}
|
|
497
|
+
const s = new Uint32Array(n + 1), o = new Uint32Array(r), i = new Uint32Array(r), a = (c, u, f) => {
|
|
498
|
+
s.fill(0);
|
|
499
|
+
for (let l = 0; l < r; l++)
|
|
500
|
+
s[c[l] + 1]++;
|
|
501
|
+
for (let l = 0; l < n; l++)
|
|
502
|
+
s[l + 1] += s[l];
|
|
503
|
+
for (let l = 0; l < r; l++) {
|
|
504
|
+
const d = u === null ? l : u[l];
|
|
505
|
+
f[s[c[d]]++] = d;
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
return a(t, null, o), a(e, o, i), { perm: i, bytes: s.byteLength + o.byteLength + i.byteLength };
|
|
509
|
+
}
|
|
510
|
+
function Vs(e, t, n, r, s) {
|
|
511
|
+
const [o, i] = e.endpoints(t);
|
|
512
|
+
return Mt(
|
|
513
|
+
{ source: e.idOf(o), target: e.idOf(i), id: r ?? $t(n) },
|
|
514
|
+
s
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
function Ct(e) {
|
|
518
|
+
const t = e.graph.typed(An, "u8");
|
|
519
|
+
return t === null ? e.directed : t.data[0] === 1;
|
|
520
|
+
}
|
|
521
|
+
function Js(e, t) {
|
|
522
|
+
if (t || typeof e != "object" || e === null)
|
|
523
|
+
return e;
|
|
524
|
+
const { source: n, target: r } = e, s = (o) => typeof o == "string" || typeof o == "number";
|
|
525
|
+
return !s(n) || !s(r) || z(r, n) >= 0 ? e : { ...e, source: r, target: n };
|
|
526
|
+
}
|
|
527
|
+
function En(e) {
|
|
528
|
+
return {
|
|
529
|
+
endpoints: (t) => [e.edgeSource(t), e.edgeTarget(t)],
|
|
530
|
+
idOf: (t) => e.ids.idOf(t)
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
const Ke = /* @__PURE__ */ new WeakMap();
|
|
534
|
+
function In(e) {
|
|
535
|
+
const t = e.nodes.typed(B.nodeHash, "u32"), n = e.edges.typed(B.edgeHash, "u32"), r = e.edges.typed(B.edgeOrdinal, "i32"), s = e.edges.typed(B.edgeAmong, "i32");
|
|
536
|
+
if (t !== null && n !== null && r !== null && s !== null)
|
|
537
|
+
return {
|
|
538
|
+
nodeHash: t.data,
|
|
539
|
+
edgeHash: n.data,
|
|
540
|
+
edgeOrdinal: r.data,
|
|
541
|
+
edgeAmong: s.data
|
|
542
|
+
};
|
|
543
|
+
let o = Ke.get(e);
|
|
544
|
+
return o === void 0 && (o = Rn(e), Ke.set(e, o)), o;
|
|
545
|
+
}
|
|
546
|
+
function Rn(e) {
|
|
547
|
+
const t = new Uint32Array(2 * e.nodeCount);
|
|
548
|
+
for (let i = 0; i < e.nodeCount; i++) {
|
|
549
|
+
const { a, b: c } = ze(e.ids.idOf(i));
|
|
550
|
+
t[2 * i] = a, t[2 * i + 1] = c;
|
|
551
|
+
}
|
|
552
|
+
const n = new Uint32Array(2 * e.edgeCount), r = new Int32Array(e.edgeCount), s = new Int32Array(e.edgeCount), o = new Uint32Array(e.edgeCount);
|
|
553
|
+
for (let i = 0; i < o.length; i++)
|
|
554
|
+
o[i] = i;
|
|
555
|
+
return Sn(
|
|
556
|
+
o,
|
|
557
|
+
En(e),
|
|
558
|
+
Ct(e),
|
|
559
|
+
() => {
|
|
560
|
+
},
|
|
561
|
+
(i, a, c, u) => {
|
|
562
|
+
r[i] = a, s[i] = c, n[2 * i] = u.a, n[2 * i + 1] = u.b;
|
|
563
|
+
}
|
|
564
|
+
), { nodeHash: t, edgeHash: n, edgeOrdinal: r, edgeAmong: s };
|
|
565
|
+
}
|
|
566
|
+
function Ws(e, t, n) {
|
|
567
|
+
let r = e.ids.idOf(e.edgeSource(t)), s = e.ids.idOf(e.edgeTarget(t));
|
|
568
|
+
if (!Ct(e) && z(s, r) < 0 && ([r, s] = [s, r]), n !== void 0)
|
|
569
|
+
return { source: r, target: s, id: n };
|
|
570
|
+
const { edgeOrdinal: o, edgeAmong: i } = In(e), a = o[t];
|
|
571
|
+
if (a >= 0)
|
|
572
|
+
return { source: r, target: s, ordinal: a, among: i[t] };
|
|
573
|
+
const c = e.edges.typed(ve, "u32");
|
|
574
|
+
if (c === null || !c.isSet(t))
|
|
575
|
+
throw new Error(`edge ${t} has neither an ordinal nor a counter to mint an id from`);
|
|
576
|
+
return { source: r, target: s, id: $t(c.data[t]) };
|
|
577
|
+
}
|
|
578
|
+
const Mn = 256 * 1024 * 1024, $n = 1.5, Ze = /* @__PURE__ */ new WeakMap();
|
|
579
|
+
let Cn = 1;
|
|
580
|
+
function _n(e) {
|
|
581
|
+
if (e === null)
|
|
582
|
+
return 0;
|
|
583
|
+
let t = Ze.get(e);
|
|
584
|
+
return t === void 0 && (t = Cn++, Ze.set(e, t)), t;
|
|
585
|
+
}
|
|
586
|
+
function Tn(e, t) {
|
|
587
|
+
let n = 2166136261, r = 16777619 ^ e.length;
|
|
588
|
+
for (const s of [e, t]) {
|
|
589
|
+
for (let o = 0; o < s.length; o++) {
|
|
590
|
+
const i = s[o];
|
|
591
|
+
n = Math.imul(n ^ i, 16777619), r = Math.imul(r ^ (i >>> 16 | i << 16), 16777619) ^ o;
|
|
592
|
+
}
|
|
593
|
+
n = Math.imul(n ^ s.length, 16777619);
|
|
594
|
+
}
|
|
595
|
+
return `${(n >>> 0).toString(16)}${(r >>> 0).toString(16)}`;
|
|
596
|
+
}
|
|
597
|
+
function Xe(e, t) {
|
|
598
|
+
if (e === t)
|
|
599
|
+
return !0;
|
|
600
|
+
if (e.length !== t.length)
|
|
601
|
+
return !1;
|
|
602
|
+
for (let n = 0; n < e.length; n++)
|
|
603
|
+
if (e[n] !== t[n])
|
|
604
|
+
return !1;
|
|
605
|
+
return !0;
|
|
606
|
+
}
|
|
607
|
+
function Qe(e) {
|
|
608
|
+
const t = /* @__PURE__ */ new Set(), n = [...e];
|
|
609
|
+
let r = 0;
|
|
610
|
+
for (; n.length > 0; ) {
|
|
611
|
+
const s = n.pop();
|
|
612
|
+
if (!(s === null || typeof s != "object" || t.has(s))) {
|
|
613
|
+
if (t.add(s), ArrayBuffer.isView(s)) {
|
|
614
|
+
r += s.byteLength;
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
if (!(s instanceof ArrayBuffer)) {
|
|
618
|
+
if (s instanceof Map)
|
|
619
|
+
for (const [o, i] of s)
|
|
620
|
+
n.push(o, i);
|
|
621
|
+
else if (s instanceof Set)
|
|
622
|
+
for (const o of s)
|
|
623
|
+
n.push(o);
|
|
624
|
+
for (const o of Reflect.ownKeys(s)) {
|
|
625
|
+
const i = Object.getOwnPropertyDescriptor(s, o);
|
|
626
|
+
i !== void 0 && "value" in i && n.push(i.value);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
return r;
|
|
632
|
+
}
|
|
633
|
+
function et(e) {
|
|
634
|
+
return e.byteLength({ columns: !0, ids: !0 });
|
|
635
|
+
}
|
|
636
|
+
class Fn {
|
|
637
|
+
/**
|
|
638
|
+
* An empty cache.
|
|
639
|
+
* @param options - The release hook and, for tests, the byte bound.
|
|
640
|
+
* @param options.release - Frees an accelerator's device buffers for a snapshot nothing uses.
|
|
641
|
+
* @param options.limit - A fixed byte bound instead of max(256 MB, 1.5 x the full snapshot).
|
|
642
|
+
*/
|
|
643
|
+
constructor(t = {}) {
|
|
644
|
+
this.options = t, this.entries = /* @__PURE__ */ new Map(), this.draining = /* @__PURE__ */ new Set(), this.reservations = /* @__PURE__ */ new Map(), this.waiters = [], this.fullBytes = 0, this.disposed = !1;
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* The byte bound now.
|
|
648
|
+
* @returns The bound.
|
|
649
|
+
*/
|
|
650
|
+
get bound() {
|
|
651
|
+
return this.options.limit ?? Math.max(Mn, Math.ceil($n * this.fullBytes));
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* The bytes the live entries hold, draining ones included.
|
|
655
|
+
* @returns The byte count.
|
|
656
|
+
*/
|
|
657
|
+
get bytes() {
|
|
658
|
+
return Qe([...this.live()].map(nt));
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Every live entry, draining ones included, least recently used first. For the accounting test.
|
|
662
|
+
* @returns The entries.
|
|
663
|
+
*/
|
|
664
|
+
list() {
|
|
665
|
+
return [...this.live()].map((t) => ({
|
|
666
|
+
key: t.key,
|
|
667
|
+
snapshot: t.snapshot,
|
|
668
|
+
edgeRemap: t.edgeRemap,
|
|
669
|
+
nodeOrigin: t.nodeOrigin,
|
|
670
|
+
nodes: t.nodes,
|
|
671
|
+
edges: t.edges,
|
|
672
|
+
held: t.holders.size > 0,
|
|
673
|
+
marked: t.marked
|
|
674
|
+
}));
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* A cached input, held for a run on a hit.
|
|
678
|
+
* @param holder - The run.
|
|
679
|
+
* @param membership - What it is derived for.
|
|
680
|
+
* @param orientation - The orientation.
|
|
681
|
+
* @param simplify - The merge policy.
|
|
682
|
+
* @returns The input, or undefined on a miss.
|
|
683
|
+
*/
|
|
684
|
+
get(t, n, r, s) {
|
|
685
|
+
this.sync(n);
|
|
686
|
+
const o = tt(n, r, s), i = this.entries.get(o);
|
|
687
|
+
if (!(i === void 0 || !Xe(i.nodes, n.nodes) || !Xe(i.edges, n.edges)))
|
|
688
|
+
return this.entries.delete(o), this.entries.set(o, i), i.holders.add(t), i;
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Cache an input a run derived, held for it, then evict unheld entries past the bound.
|
|
692
|
+
* @param holder - The run.
|
|
693
|
+
* @param membership - What it was derived for.
|
|
694
|
+
* @param orientation - The orientation.
|
|
695
|
+
* @param simplify - The merge policy.
|
|
696
|
+
* @param input - The derived input.
|
|
697
|
+
* @param full - The full snapshot it was derived from, whose bytes set the bound.
|
|
698
|
+
* @returns The input.
|
|
699
|
+
*/
|
|
700
|
+
put(t, n, r, s, o, i) {
|
|
701
|
+
this.sync(n), this.fullBytes = et(i);
|
|
702
|
+
const a = tt(n, r, s), c = this.entries.get(a);
|
|
703
|
+
c !== void 0 && (this.entries.delete(a), this.evictEntry(c));
|
|
704
|
+
const u = {
|
|
705
|
+
...o,
|
|
706
|
+
key: a,
|
|
707
|
+
serial: n.serial,
|
|
708
|
+
store: n.store,
|
|
709
|
+
nodes: n.nodes,
|
|
710
|
+
edges: n.edges,
|
|
711
|
+
holders: /* @__PURE__ */ new Set([t]),
|
|
712
|
+
marked: this.disposed
|
|
713
|
+
};
|
|
714
|
+
return this.disposed ? this.draining.add(u) : (this.entries.set(a, u), this.shrink()), u;
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Reserve room for a run's derivation before it starts. Evicts unheld entries to make room;
|
|
718
|
+
* waits while a DIFFERENT run holds or reserves what would free it; refuses `E_TOO_LARGE`
|
|
719
|
+
* when nothing else holds anything and it still does not fit. A run that already holds an
|
|
720
|
+
* input is admitted at once: it never waits on itself.
|
|
721
|
+
* @param holder - The run.
|
|
722
|
+
* @param estimate - The bytes its derivation is expected to take.
|
|
723
|
+
* @param full - The full snapshot, whose bytes set the bound.
|
|
724
|
+
* @param signal - Aborts the wait.
|
|
725
|
+
* @returns Resolves once the run may derive.
|
|
726
|
+
*/
|
|
727
|
+
async reserve(t, n, r, s) {
|
|
728
|
+
for (this.fullBytes = et(r); ; ) {
|
|
729
|
+
if (s?.throwIfAborted(), this.holds(t))
|
|
730
|
+
return;
|
|
731
|
+
const o = this.bound - this.pending(t) - n;
|
|
732
|
+
if (this.shrink(o), this.bytes <= o) {
|
|
733
|
+
this.reservations.set(t, n);
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
if (!this.othersHold(t))
|
|
737
|
+
throw new g({
|
|
738
|
+
code: "E_TOO_LARGE",
|
|
739
|
+
message: `A scoped run needs about ${String(n)} bytes for its input, and the derived-input cache holds at most ${String(this.bound)}.`,
|
|
740
|
+
source: "run",
|
|
741
|
+
details: { reason: "derived-input", estimate: n, bound: this.bound }
|
|
742
|
+
});
|
|
743
|
+
await this.nextRelease(s);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* A run published or aborted: it lets go of every input it held and its reservation. A marked
|
|
748
|
+
* input with no holder left is released; waiting runs try again.
|
|
749
|
+
* @param holder - The run.
|
|
750
|
+
*/
|
|
751
|
+
releaseHolder(t) {
|
|
752
|
+
this.reservations.delete(t);
|
|
753
|
+
for (const n of [...this.live()])
|
|
754
|
+
n.holders.delete(t) && n.holders.size === 0 && n.marked && this.free(n);
|
|
755
|
+
this.shrink(), this.wake();
|
|
756
|
+
}
|
|
757
|
+
/** The graph froze: every entry is over a snapshot that has gone. */
|
|
758
|
+
freeze() {
|
|
759
|
+
for (const t of [...this.entries.values()])
|
|
760
|
+
this.entries.delete(t.key), this.evictEntry(t);
|
|
761
|
+
this.wake();
|
|
762
|
+
}
|
|
763
|
+
/** The graph is being torn down: release what nothing holds, mark the rest, cache nothing more. */
|
|
764
|
+
dispose() {
|
|
765
|
+
this.disposed = !0, this.freeze();
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Mark every entry over another snapshot or store than this membership's.
|
|
769
|
+
* @param membership - The membership now being asked for.
|
|
770
|
+
*/
|
|
771
|
+
sync(t) {
|
|
772
|
+
for (const n of [...this.entries.values()])
|
|
773
|
+
(n.serial !== t.serial || n.store !== t.store) && (this.entries.delete(n.key), this.evictEntry(n));
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Evict unheld entries, least recently used first, until the bytes fit.
|
|
777
|
+
* @param budget - The bytes to fit in; the bound by default.
|
|
778
|
+
*/
|
|
779
|
+
shrink(t = this.bound) {
|
|
780
|
+
for (const n of [...this.entries.values()]) {
|
|
781
|
+
if (this.bytes <= t)
|
|
782
|
+
return;
|
|
783
|
+
n.holders.size === 0 && (this.entries.delete(n.key), this.evictEntry(n));
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Take an entry out of the cache: released at once when unheld, else marked and drained.
|
|
788
|
+
* @param entry - It.
|
|
789
|
+
*/
|
|
790
|
+
evictEntry(t) {
|
|
791
|
+
t.marked = !0, t.holders.size === 0 ? this.free(t) : this.draining.add(t);
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Release an entry's snapshot, unless another live entry still reaches the same one.
|
|
795
|
+
* @param entry - It.
|
|
796
|
+
*/
|
|
797
|
+
free(t) {
|
|
798
|
+
this.draining.delete(t);
|
|
799
|
+
for (const n of this.live())
|
|
800
|
+
if (n !== t && n.snapshot === t.snapshot)
|
|
801
|
+
return;
|
|
802
|
+
this.options.release?.(t.snapshot);
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Every live entry: cached and draining.
|
|
806
|
+
* @yields Each entry.
|
|
807
|
+
*/
|
|
808
|
+
*live() {
|
|
809
|
+
yield* this.entries.values(), yield* this.draining;
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Whether a run holds anything.
|
|
813
|
+
* @param holder - The run.
|
|
814
|
+
* @returns True when it does.
|
|
815
|
+
*/
|
|
816
|
+
holds(t) {
|
|
817
|
+
for (const n of this.live())
|
|
818
|
+
if (n.holders.has(t))
|
|
819
|
+
return !0;
|
|
820
|
+
return !1;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Whether a run other than this one holds an input or a reservation.
|
|
824
|
+
* @param holder - The run asking.
|
|
825
|
+
* @returns True when another does.
|
|
826
|
+
*/
|
|
827
|
+
othersHold(t) {
|
|
828
|
+
for (const n of this.reservations.keys())
|
|
829
|
+
if (n !== t)
|
|
830
|
+
return !0;
|
|
831
|
+
for (const n of this.live())
|
|
832
|
+
for (const r of n.holders)
|
|
833
|
+
if (r !== t)
|
|
834
|
+
return !0;
|
|
835
|
+
return !1;
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* The bytes other runs reserved and have not yet derived.
|
|
839
|
+
* @param holder - The run asking, left out.
|
|
840
|
+
* @returns The byte count.
|
|
841
|
+
*/
|
|
842
|
+
pending(t) {
|
|
843
|
+
let n = 0;
|
|
844
|
+
for (const [r, s] of this.reservations) {
|
|
845
|
+
if (r === t)
|
|
846
|
+
continue;
|
|
847
|
+
const o = Qe([...this.live()].filter((i) => i.holders.has(r)).map(nt));
|
|
848
|
+
n += Math.max(0, s - o);
|
|
849
|
+
}
|
|
850
|
+
return n;
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Resolves the next time a run lets go or the graph freezes.
|
|
854
|
+
* @param signal - Rejects the wait when aborted.
|
|
855
|
+
* @returns The wait.
|
|
856
|
+
*/
|
|
857
|
+
nextRelease(t) {
|
|
858
|
+
return new Promise((n, r) => {
|
|
859
|
+
const s = () => {
|
|
860
|
+
this.waiters = this.waiters.filter((i) => i !== o), r(
|
|
861
|
+
t?.reason instanceof Error ? t.reason : new DOMException("The run was cancelled.", "AbortError")
|
|
862
|
+
);
|
|
863
|
+
}, o = () => {
|
|
864
|
+
t?.removeEventListener("abort", s), n();
|
|
865
|
+
};
|
|
866
|
+
this.waiters.push(o), t?.addEventListener("abort", s, { once: !0 });
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
/** Let every waiting run try again. */
|
|
870
|
+
wake() {
|
|
871
|
+
const t = this.waiters;
|
|
872
|
+
this.waiters = [];
|
|
873
|
+
for (const n of t)
|
|
874
|
+
n();
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
function tt(e, t, n) {
|
|
878
|
+
return `${String(_n(e.store))}:${String(e.serial)}:${Tn(e.nodes, e.edges)}:${t}:${n}`;
|
|
879
|
+
}
|
|
880
|
+
function nt(e) {
|
|
881
|
+
return [e.snapshot, e.edgeRemap, e.nodeOrigin, e.nodes, e.edges];
|
|
882
|
+
}
|
|
883
|
+
const re = /* @__PURE__ */ new WeakMap();
|
|
884
|
+
function Le(e) {
|
|
885
|
+
return e.constructor.scopeInput === "subgraph";
|
|
886
|
+
}
|
|
887
|
+
function xn(e) {
|
|
888
|
+
return Le(e) ? re.get(e) : void 0;
|
|
889
|
+
}
|
|
890
|
+
function zn(e) {
|
|
891
|
+
return re.get(e)?.scope() ?? null;
|
|
892
|
+
}
|
|
893
|
+
function Oe(e) {
|
|
894
|
+
return e === "undirected" ? "undirected" : "declared";
|
|
895
|
+
}
|
|
896
|
+
function _t(e, t) {
|
|
897
|
+
if (t === null)
|
|
898
|
+
return e;
|
|
899
|
+
if (e === null)
|
|
900
|
+
return t;
|
|
901
|
+
const n = new Uint32Array(e.length);
|
|
902
|
+
for (let r = 0; r < e.length; r++) {
|
|
903
|
+
const s = e[r];
|
|
904
|
+
n[r] = s === E ? E : t[s];
|
|
905
|
+
}
|
|
906
|
+
return n;
|
|
907
|
+
}
|
|
908
|
+
function Ln(e, t, n, r) {
|
|
909
|
+
const s = n === "undirected" ? e.undirected(t) : null, o = s === null ? t : s.snapshot, i = r !== "none" && o.flags.multigraph ? o.simplified({ weights: r }) : null;
|
|
910
|
+
return {
|
|
911
|
+
snapshot: i === null ? o : i.snapshot,
|
|
912
|
+
edgeRemap: _t(s?.edgeRemap ?? null, i?.edgeRemap ?? null),
|
|
913
|
+
nodeOrigin: null
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
function ke(e, t) {
|
|
917
|
+
return {
|
|
918
|
+
snapshot: t.snapshot,
|
|
919
|
+
edgeRemap: _t(e.edgeRemap, t.edgeRemap),
|
|
920
|
+
nodeOrigin: e.nodeOrigin
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
function jn(e, t) {
|
|
924
|
+
const n = t.inducedSubgraph({ mask: e.nodes }), r = n.edgeRemap, s = he(n.snapshot.edgeCount);
|
|
925
|
+
let o = 0;
|
|
926
|
+
const { edges: i } = e;
|
|
927
|
+
for (let c = 0; c < i.length; c++) {
|
|
928
|
+
let u = i[c];
|
|
929
|
+
for (; u !== 0; ) {
|
|
930
|
+
const f = u & -u, l = c * 32 + (31 - Math.clz32(f));
|
|
931
|
+
if (u ^= f, l >= t.edgeCount)
|
|
932
|
+
continue;
|
|
933
|
+
const d = r === null ? l : r[l];
|
|
934
|
+
d !== E && (s[d >>> 5] |= 1 << (d & 31), o++);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
const a = { snapshot: n.snapshot, edgeRemap: r, nodeOrigin: n.nodeOrigin };
|
|
938
|
+
return o === n.snapshot.edgeCount ? a : ke(a, n.snapshot.filterEdges(s));
|
|
939
|
+
}
|
|
940
|
+
function Dn(e, t, n, r, s) {
|
|
941
|
+
const { inputs: o, holder: i } = e, a = o.get(i, t, r, s);
|
|
942
|
+
if (a !== void 0)
|
|
943
|
+
return a;
|
|
944
|
+
const c = o.get(i, t, "declared", "none") ?? o.put(i, t, "declared", "none", jn(t, n), n);
|
|
945
|
+
let u = c;
|
|
946
|
+
return r === "undirected" && u.snapshot.directed && (u = ke(u, u.snapshot.toUndirected())), s !== "none" && u.snapshot.flags.multigraph && (u = ke(u, u.snapshot.simplified({ weights: s }))), u === c ? c : o.put(i, t, r, s, u, n);
|
|
947
|
+
}
|
|
948
|
+
function Tt(e, t, n, r) {
|
|
949
|
+
const s = e.getSnapshot(), o = n?.simplify ?? "sum", i = r?.scope() ?? null;
|
|
950
|
+
if (i !== null && i.graph !== s)
|
|
951
|
+
throw new Error("A run's scope was resolved against a snapshot that is no longer the graph.");
|
|
952
|
+
const a = i?.resolution, c = a === void 0 || a.nodeCount === s.nodeCount && a.edgeCount === s.edgeCount ? null : a;
|
|
953
|
+
let u = null, f = c?.nodes ?? null, l = c?.edges ?? null;
|
|
954
|
+
const d = {
|
|
955
|
+
graph: s,
|
|
956
|
+
whole: c === null,
|
|
957
|
+
nodeCount: c?.nodeCount ?? s.nodeCount,
|
|
958
|
+
edgeCount: c?.edgeCount ?? s.edgeCount,
|
|
959
|
+
derived() {
|
|
960
|
+
return u ??= c === null || r === void 0 ? Ln(e, s, t, o) : Dn(r, c, s, t, o), u;
|
|
961
|
+
},
|
|
962
|
+
subgraph() {
|
|
963
|
+
return d.derived().snapshot;
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
return Object.defineProperties(d, {
|
|
967
|
+
nodes: {
|
|
968
|
+
enumerable: !0,
|
|
969
|
+
get: () => (f ??= he(s.nodeCount, !0), f)
|
|
970
|
+
},
|
|
971
|
+
edges: {
|
|
972
|
+
enumerable: !0,
|
|
973
|
+
get: () => (l ??= he(s.edgeCount, !0), l)
|
|
974
|
+
}
|
|
975
|
+
}), d;
|
|
976
|
+
}
|
|
977
|
+
function Ys(e) {
|
|
978
|
+
const { graph: t, nodes: n, whole: r } = e, s = [];
|
|
979
|
+
for (let o = 0; o < t.nodeCount; o++)
|
|
980
|
+
(r || oe(n, o)) && s.push(t.ids.idOf(o));
|
|
981
|
+
return s;
|
|
982
|
+
}
|
|
983
|
+
function qs(e) {
|
|
984
|
+
const { graph: t, edges: n, whole: r } = e, s = t.edges.typed(ve, "u32");
|
|
985
|
+
if (s === null)
|
|
986
|
+
throw new Error(`The graph carries no "${ve}" column to name its edges by.`);
|
|
987
|
+
const { src: o, dst: i } = t.edgeList(), a = [];
|
|
988
|
+
for (let c = 0; c < t.edgeCount; c++)
|
|
989
|
+
(r || oe(n, c)) && a.push({
|
|
990
|
+
id: vn(s.data[c]),
|
|
991
|
+
row: c,
|
|
992
|
+
source: t.ids.idOf(o[c]),
|
|
993
|
+
target: t.ids.idOf(i[c])
|
|
994
|
+
});
|
|
995
|
+
return a;
|
|
996
|
+
}
|
|
997
|
+
const Ae = /* @__PURE__ */ new WeakMap();
|
|
998
|
+
function Pn(e) {
|
|
999
|
+
let t = Ae.get(e);
|
|
1000
|
+
return t === void 0 && (t = new Fn({
|
|
1001
|
+
release: (n) => {
|
|
1002
|
+
const { accelerator: r } = e.acceleration, s = r?.release;
|
|
1003
|
+
if (typeof s == "function")
|
|
1004
|
+
try {
|
|
1005
|
+
s.call(r, n);
|
|
1006
|
+
} catch (o) {
|
|
1007
|
+
console.warn("graphty: an accelerator threw while releasing a derived input", o);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}), Ae.set(e, t)), t;
|
|
1011
|
+
}
|
|
1012
|
+
function Ks(e) {
|
|
1013
|
+
return Ae.get(e);
|
|
1014
|
+
}
|
|
1015
|
+
function Hn(e) {
|
|
1016
|
+
const { graph: t, resolution: n } = e, r = t.nodeCount + t.edgeCount, s = t.byteLength({ columns: !0, ids: !0 });
|
|
1017
|
+
return r === 0 ? 0 : Math.ceil(s * (n.nodeCount + n.edgeCount) / r);
|
|
1018
|
+
}
|
|
1019
|
+
async function Zs(e, t, n, r, s) {
|
|
1020
|
+
const o = Pn(t), i = {};
|
|
1021
|
+
re.set(e, { inputs: o, holder: i, scope: n });
|
|
1022
|
+
try {
|
|
1023
|
+
if (Le(e)) {
|
|
1024
|
+
const a = n();
|
|
1025
|
+
a !== null && (a.resolution.nodeCount !== a.graph.nodeCount || a.resolution.edgeCount !== a.graph.edgeCount) && await o.reserve(i, Hn(a), a.graph, r);
|
|
1026
|
+
}
|
|
1027
|
+
return await s();
|
|
1028
|
+
} finally {
|
|
1029
|
+
re.delete(e), o.releaseHolder(i);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
class O extends Error {
|
|
1033
|
+
/**
|
|
1034
|
+
* Creates an option validation error
|
|
1035
|
+
* @param optionKey - The key of the option that failed validation
|
|
1036
|
+
* @param message - The validation error message
|
|
1037
|
+
*/
|
|
1038
|
+
constructor(t, n) {
|
|
1039
|
+
super(`Option '${t}': ${n}`), this.optionKey = t, this.name = "OptionValidationError";
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
function Un(e, t, n) {
|
|
1043
|
+
if (t == null) {
|
|
1044
|
+
if (n.required)
|
|
1045
|
+
throw new O(e, "is required but was not provided");
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
switch (n.type) {
|
|
1049
|
+
case "number":
|
|
1050
|
+
rt(e, t, n, !1);
|
|
1051
|
+
break;
|
|
1052
|
+
case "integer":
|
|
1053
|
+
rt(e, t, n, !0);
|
|
1054
|
+
break;
|
|
1055
|
+
case "boolean":
|
|
1056
|
+
if (typeof t != "boolean")
|
|
1057
|
+
throw new O(e, `must be a boolean, got ${typeof t}`);
|
|
1058
|
+
break;
|
|
1059
|
+
case "string":
|
|
1060
|
+
if (typeof t != "string")
|
|
1061
|
+
throw new O(e, `must be a string, got ${typeof t}`);
|
|
1062
|
+
break;
|
|
1063
|
+
case "select":
|
|
1064
|
+
Gn(e, t, n);
|
|
1065
|
+
break;
|
|
1066
|
+
case "nodeId":
|
|
1067
|
+
if (typeof t != "string" && typeof t != "number")
|
|
1068
|
+
throw new O(e, `must be a string or number (node ID), got ${typeof t}`);
|
|
1069
|
+
break;
|
|
1070
|
+
default:
|
|
1071
|
+
throw new O(e, `has unknown type '${n.type}'`);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
function rt(e, t, n, r) {
|
|
1075
|
+
if (typeof t != "number")
|
|
1076
|
+
throw new O(e, `must be a number, got ${typeof t}`);
|
|
1077
|
+
if (Number.isNaN(t))
|
|
1078
|
+
throw new O(e, "must not be NaN");
|
|
1079
|
+
if (!Number.isFinite(t))
|
|
1080
|
+
throw new O(e, "must be finite");
|
|
1081
|
+
if (r && !Number.isInteger(t))
|
|
1082
|
+
throw new O(e, `must be an integer, got ${t}`);
|
|
1083
|
+
if (n.min !== void 0 && t < n.min)
|
|
1084
|
+
throw new O(e, `must be >= ${n.min}, got ${t}`);
|
|
1085
|
+
if (n.max !== void 0 && t > n.max)
|
|
1086
|
+
throw new O(e, `must be <= ${n.max}, got ${t}`);
|
|
1087
|
+
}
|
|
1088
|
+
function Gn(e, t, n) {
|
|
1089
|
+
if (!n.options || n.options.length === 0)
|
|
1090
|
+
throw new O(e, "is a select type but has no options defined");
|
|
1091
|
+
if (!n.options.map((s) => s.value).includes(t)) {
|
|
1092
|
+
const s = n.options.map((o) => `'${String(o.value)}'`).join(", ");
|
|
1093
|
+
throw new O(e, `must be one of [${s}], got '${String(t)}'`);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
function Bn(e, t) {
|
|
1097
|
+
const n = {};
|
|
1098
|
+
for (const [r, s] of Object.entries(e)) {
|
|
1099
|
+
const i = t?.[r] ?? s.default;
|
|
1100
|
+
Un(r, i, s), n[r] = i;
|
|
1101
|
+
}
|
|
1102
|
+
return n;
|
|
1103
|
+
}
|
|
1104
|
+
function Xs(e) {
|
|
1105
|
+
return e;
|
|
1106
|
+
}
|
|
1107
|
+
function Vn(e, t, n = Tt(e, Oe(t))) {
|
|
1108
|
+
return Jn(n.subgraph(), t);
|
|
1109
|
+
}
|
|
1110
|
+
function Qs(e) {
|
|
1111
|
+
const t = e.getSnapshot();
|
|
1112
|
+
return t.flags.multigraph ? t.edgeCount - t.simplified({ weights: "sum" }).snapshot.edgeCount : 0;
|
|
1113
|
+
}
|
|
1114
|
+
function Jn(e, t) {
|
|
1115
|
+
const n = new tn({
|
|
1116
|
+
directed: t !== "undirected"
|
|
1117
|
+
}), { ids: r } = e;
|
|
1118
|
+
for (let a = 0; a < e.nodeCount; a++)
|
|
1119
|
+
n.addNode(r.idOf(a));
|
|
1120
|
+
const { src: s, dst: o, weights: i } = e.edgeList();
|
|
1121
|
+
for (let a = 0; a < e.edgeCount; a++) {
|
|
1122
|
+
const c = r.idOf(s[a]), u = r.idOf(o[a]), f = i === null ? 1 : i[a];
|
|
1123
|
+
n.addEdge(c, u, f);
|
|
1124
|
+
}
|
|
1125
|
+
return n;
|
|
1126
|
+
}
|
|
1127
|
+
const V = new Zt("algorithm"), st = /* @__PURE__ */ new WeakMap();
|
|
1128
|
+
function Wn(e, t, n) {
|
|
1129
|
+
if (e.scopeInput !== void 0 && e.scopeInput !== t)
|
|
1130
|
+
throw new g({
|
|
1131
|
+
code: "E_BAD_COMMAND",
|
|
1132
|
+
message: `the algorithm registered as "${n}" publishes scopeInput "${e.scopeInput}" and its class declares "${t}". Declare it once, as "static scopeInput", and leave it out of the descriptor.`,
|
|
1133
|
+
source: "registry",
|
|
1134
|
+
details: {
|
|
1135
|
+
kind: "algorithm",
|
|
1136
|
+
field: "descriptor.scopeInput",
|
|
1137
|
+
key: e.key,
|
|
1138
|
+
declared: t,
|
|
1139
|
+
published: e.scopeInput
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1142
|
+
let r = st.get(e);
|
|
1143
|
+
r === void 0 && (r = /* @__PURE__ */ new Map(), st.set(e, r));
|
|
1144
|
+
let s = r.get(t);
|
|
1145
|
+
return s === void 0 && (s = { ...e, scopeInput: t }, r.set(t, s)), s;
|
|
1146
|
+
}
|
|
1147
|
+
const Ge = class Ge {
|
|
1148
|
+
/**
|
|
1149
|
+
* Getter for schema options
|
|
1150
|
+
*
|
|
1151
|
+
* Algorithms that use the new schema-based options should access
|
|
1152
|
+
* options via this getter.
|
|
1153
|
+
* @returns The resolved schema options
|
|
1154
|
+
*/
|
|
1155
|
+
get schemaOptions() {
|
|
1156
|
+
return this._schemaOptions;
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Creates a new algorithm instance
|
|
1160
|
+
* @param g - The graph to run the algorithm on
|
|
1161
|
+
* @param options - Optional configuration options (uses schema defaults if not provided)
|
|
1162
|
+
*/
|
|
1163
|
+
constructor(t, n) {
|
|
1164
|
+
this.graph = t, this._schemaOptions = this.resolveOptions(n);
|
|
1165
|
+
}
|
|
1166
|
+
/**
|
|
1167
|
+
* The `@graphty/algorithms` Graph this run reads, built from the element's graph snapshot.
|
|
1168
|
+
*
|
|
1169
|
+
* This is the ONLY way an algorithm should obtain its input. The `Node` and `Edge` objects the
|
|
1170
|
+
* data manager also holds are render objects -- each `Node` builds a Babylon mesh in its
|
|
1171
|
+
* constructor -- and reading the graph out of them ties every algorithm to a renderer and to
|
|
1172
|
+
* whatever part of a data load the scene has caught up with.
|
|
1173
|
+
* @param mode - the shape this algorithm needs; see {@link AlgorithmGraphMode}
|
|
1174
|
+
* @returns a freshly built Graph for the algorithm package
|
|
1175
|
+
*/
|
|
1176
|
+
algorithmGraph(t) {
|
|
1177
|
+
return Vn(this.graph.getDataManager(), t, this.input(Oe(t)));
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* The graph this run computes over, in one orientation: its scope's compact snapshot when the
|
|
1181
|
+
* class declares {@link Algorithm.scopeInput} and runs as a run, else the whole graph. Both
|
|
1182
|
+
* seams below read through it.
|
|
1183
|
+
* @param orientation - `"declared"` or `"undirected"`.
|
|
1184
|
+
* @param options - How parallel edges merge; the class's {@link Algorithm.parallelEdges} by
|
|
1185
|
+
* default, else `"sum"`.
|
|
1186
|
+
* @returns The input.
|
|
1187
|
+
* @internal
|
|
1188
|
+
*/
|
|
1189
|
+
input(t, n) {
|
|
1190
|
+
const r = n?.simplify ?? this.constructor.parallelEdges, s = r === void 0 ? n : { ...n, simplify: r };
|
|
1191
|
+
return Tt(this.graph.getDataManager(), t, s, xn(this));
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* One edge's record, by the id an input named it by: for an attribute the snapshot does not
|
|
1195
|
+
* carry yet, such as a flow capacity. It is not a topology read -- the ids come from the input
|
|
1196
|
+
* -- and it goes away once the store carries attribute columns.
|
|
1197
|
+
* @param id - The edge's session id, from `scopeEdges`.
|
|
1198
|
+
* @returns The record the edge was loaded from, or undefined.
|
|
1199
|
+
* @internal
|
|
1200
|
+
*/
|
|
1201
|
+
edgeRecord(t) {
|
|
1202
|
+
return this.graph.getDataManager().getEdge(t)?.data;
|
|
1203
|
+
}
|
|
1204
|
+
/**
|
|
1205
|
+
* The route an algorithm with an accelerated implementation takes.
|
|
1206
|
+
*
|
|
1207
|
+
* It is the counterpart of {@link algorithmGraph} for the algorithms `@graphty/algorithms`
|
|
1208
|
+
* can dispatch: instead of copying the snapshot into an object graph, the work runs over the
|
|
1209
|
+
* snapshot itself, on the attached accelerator or on the index-based CPU port, and the adapter
|
|
1210
|
+
* writes one loop over an index-aligned result either way.
|
|
1211
|
+
*
|
|
1212
|
+
* THE DECISION IS TAKEN ONCE, HERE, BEFORE ANY WORK STARTS. The controller answers "the policy
|
|
1213
|
+
* is off", "no accelerator", "below `acceleration.minNodes`" or "this accelerator does not
|
|
1214
|
+
* implement that" up front, and under `acceleration="required"` it throws `E_NO_ACCELERATOR`
|
|
1215
|
+
* rather than answering quietly. After the work has started there is no second decision: a
|
|
1216
|
+
* failure from the accelerator propagates with its code and fails the run, because a number
|
|
1217
|
+
* that silently came from somewhere else is worse than no number.
|
|
1218
|
+
* @param capability - The accelerator member this work would use, such as `"pageRank"`.
|
|
1219
|
+
* @param mode - The shape this algorithm needs; see {@link AlgorithmGraphMode}. `"undirected"`
|
|
1220
|
+
* takes the snapshot's undirected view, which is what collapses a reciprocal pair into one
|
|
1221
|
+
* edge.
|
|
1222
|
+
* @returns The snapshot, the edge map onto it, and the runner.
|
|
1223
|
+
* @example
|
|
1224
|
+
* ```ts
|
|
1225
|
+
* const { snapshot, run } = this.accelerated("connectedComponents", "undirected");
|
|
1226
|
+
* const { value, precision } = await run((dispatch, s) => dispatch.connectedComponents(s));
|
|
1227
|
+
* const group = value.labels[snapshot.ids.indexOf(nodeId)];
|
|
1228
|
+
* ```
|
|
1229
|
+
*/
|
|
1230
|
+
accelerated(t, n) {
|
|
1231
|
+
const { snapshot: r, edgeRemap: s } = this.input(Oe(n)).derived(), o = this.graph.acceleration, i = { capability: t, nodeCount: r.nodeCount };
|
|
1232
|
+
return {
|
|
1233
|
+
snapshot: r,
|
|
1234
|
+
edgeRemap: s,
|
|
1235
|
+
run: async (a) => {
|
|
1236
|
+
const c = await o.run(
|
|
1237
|
+
i,
|
|
1238
|
+
(u) => a(Je(sn(u)), r)
|
|
1239
|
+
);
|
|
1240
|
+
return c.accelerated ? { value: c.value, precision: c.precision } : { value: await a(Je(null), r), precision: an };
|
|
1241
|
+
}
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* The dense row of a node the reader named in an option.
|
|
1246
|
+
*
|
|
1247
|
+
* A search takes its source as an id and the snapshot answers in indices, so this is where the
|
|
1248
|
+
* two meet -- and where an id that names no node in the graph is reported as what it is: an
|
|
1249
|
+
* option whose value is outside the permitted range, carrying the option's name and what was
|
|
1250
|
+
* passed, rather than a silent empty result or a search from row zero.
|
|
1251
|
+
* @param snapshot - The graph the work runs over.
|
|
1252
|
+
* @param option - The option the id came from, named in the error.
|
|
1253
|
+
* @param id - The node id the reader gave.
|
|
1254
|
+
* @returns The node's dense row.
|
|
1255
|
+
* @throws A `GraphtyError` with `E_OPTION_RANGE` when the graph has no such node.
|
|
1256
|
+
*/
|
|
1257
|
+
nodeIndex(t, n, r) {
|
|
1258
|
+
const s = t.ids.indexOf(r);
|
|
1259
|
+
if (s === E)
|
|
1260
|
+
throw new g({
|
|
1261
|
+
code: "E_OPTION_RANGE",
|
|
1262
|
+
message: `the graph has no node "${String(r)}", so "${n}" names nothing to run from`,
|
|
1263
|
+
source: "run",
|
|
1264
|
+
details: { option: n, value: r }
|
|
1265
|
+
});
|
|
1266
|
+
return s;
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Resolves and validates options against the schema
|
|
1270
|
+
* @param options - User-provided options (partial)
|
|
1271
|
+
* @returns Fully resolved options with defaults applied
|
|
1272
|
+
*/
|
|
1273
|
+
resolveOptions(t) {
|
|
1274
|
+
const n = this.constructor.optionsSchema;
|
|
1275
|
+
return Object.keys(n).length === 0 ? {} : Bn(n, t);
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Gets the algorithm type
|
|
1279
|
+
* @returns The algorithm type identifier
|
|
1280
|
+
*/
|
|
1281
|
+
get type() {
|
|
1282
|
+
return this.constructor.type;
|
|
1283
|
+
}
|
|
1284
|
+
/**
|
|
1285
|
+
* Gets the algorithm namespace
|
|
1286
|
+
* @returns The algorithm namespace identifier
|
|
1287
|
+
*/
|
|
1288
|
+
get namespace() {
|
|
1289
|
+
return this.constructor.namespace;
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Compute this algorithm and publish what it produced as a result object.
|
|
1293
|
+
*
|
|
1294
|
+
* This is the entry point the run machinery calls, and it is the one that makes an algorithm
|
|
1295
|
+
* startable as a `Run`: it takes a signal it must throw from, a progress channel, a yield, and
|
|
1296
|
+
* the run id the result is published under -- and it RETURNS the result rather than writing it
|
|
1297
|
+
* somewhere a caller has to go looking for. `run()` is the 1.10 entry point beside it, which
|
|
1298
|
+
* returns nothing and can be neither watched nor stopped.
|
|
1299
|
+
*
|
|
1300
|
+
* The default refuses, because an algorithm that has not been migrated genuinely cannot answer
|
|
1301
|
+
* a run: it publishes through side effects under its own names and has no result object to
|
|
1302
|
+
* hand back. Both shipped families -- a metric and a declared algorithm -- override it.
|
|
1303
|
+
* @param _context - A signal, a progress channel and a yield.
|
|
1304
|
+
* @param runId - The id the result is published under.
|
|
1305
|
+
* @param _fields - The catalogue's descriptors for this algorithm's fields, when the caller
|
|
1306
|
+
* holds them.
|
|
1307
|
+
* @returns The result, or undefined when there was nothing to compute.
|
|
1308
|
+
* @throws A `GraphtyError` with code `E_UNSUPPORTED` when this algorithm has no result to
|
|
1309
|
+
* publish.
|
|
1310
|
+
*/
|
|
1311
|
+
publishResult(t, n, r) {
|
|
1312
|
+
return Promise.reject(
|
|
1313
|
+
new g({
|
|
1314
|
+
code: "E_UNSUPPORTED",
|
|
1315
|
+
message: `The "${this.namespace}:${this.type}" algorithm writes its result through side effects and cannot be started as a run.`,
|
|
1316
|
+
source: "run",
|
|
1317
|
+
target: { kind: "run", id: n },
|
|
1318
|
+
details: { algorithm: `${this.namespace}:${this.type}` }
|
|
1319
|
+
})
|
|
1320
|
+
);
|
|
1321
|
+
}
|
|
1322
|
+
/**
|
|
1323
|
+
* Registers an algorithm class in the global registry
|
|
1324
|
+
* @param cls - The algorithm class to register
|
|
1325
|
+
* @returns The registered algorithm class
|
|
1326
|
+
*/
|
|
1327
|
+
static register(t) {
|
|
1328
|
+
const n = t, r = String(n.type), s = String(n.namespace), { descriptor: o, cost: i, costUnits: a, version: c } = n;
|
|
1329
|
+
return o !== void 0 && cn({
|
|
1330
|
+
descriptor: Wn(o, n.scopeInput ?? "none", `${s}:${r}`),
|
|
1331
|
+
namespace: s,
|
|
1332
|
+
type: r,
|
|
1333
|
+
...i === void 0 ? {} : { cost: i },
|
|
1334
|
+
...a === void 0 ? {} : { costUnits: a },
|
|
1335
|
+
...c === void 0 ? {} : { version: c }
|
|
1336
|
+
}), V.set(`${s}:${r}`, t), t;
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Gets an algorithm instance from the registry
|
|
1340
|
+
* @param g - The graph to run the algorithm on
|
|
1341
|
+
* @param namespace - The algorithm namespace
|
|
1342
|
+
* @param type - The algorithm type
|
|
1343
|
+
* @param options - Optional algorithm-specific options to pass to constructor
|
|
1344
|
+
* @returns A new instance of the algorithm, or null if not found
|
|
1345
|
+
*/
|
|
1346
|
+
static get(t, n, r, s) {
|
|
1347
|
+
const o = V.get(`${n}:${r}`);
|
|
1348
|
+
return o ? new o(t, s) : null;
|
|
1349
|
+
}
|
|
1350
|
+
/**
|
|
1351
|
+
* Gets an algorithm class from the registry
|
|
1352
|
+
* @param namespace - The algorithm namespace
|
|
1353
|
+
* @param type - The algorithm type
|
|
1354
|
+
* @returns The algorithm class, or null if not found
|
|
1355
|
+
*/
|
|
1356
|
+
static getClass(t, n) {
|
|
1357
|
+
return V.get(`${t}:${n}`) ?? null;
|
|
1358
|
+
}
|
|
1359
|
+
/**
|
|
1360
|
+
* Get the options schema for this algorithm
|
|
1361
|
+
* @returns The options schema, or an empty object if no options defined
|
|
1362
|
+
* @deprecated Use getZodOptionsSchema() instead
|
|
1363
|
+
*/
|
|
1364
|
+
static getOptionsSchema() {
|
|
1365
|
+
return this.optionsSchema;
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* Check if this algorithm has configurable options
|
|
1369
|
+
* @returns true if the algorithm has at least one option defined
|
|
1370
|
+
* @deprecated Use hasZodOptions() instead
|
|
1371
|
+
*/
|
|
1372
|
+
static hasOptions() {
|
|
1373
|
+
return Object.keys(this.optionsSchema).length > 0;
|
|
1374
|
+
}
|
|
1375
|
+
/**
|
|
1376
|
+
* Get the Zod-based options schema for this algorithm.
|
|
1377
|
+
* @returns The Zod options schema, or an empty object if no schema defined
|
|
1378
|
+
*/
|
|
1379
|
+
static getZodOptionsSchema() {
|
|
1380
|
+
return this.zodOptionsSchema ?? {};
|
|
1381
|
+
}
|
|
1382
|
+
/**
|
|
1383
|
+
* Check if this algorithm has a Zod-based options schema.
|
|
1384
|
+
* @returns true if the algorithm has a Zod options schema defined
|
|
1385
|
+
*/
|
|
1386
|
+
static hasZodOptions() {
|
|
1387
|
+
return this.zodOptionsSchema !== void 0 && Object.keys(this.zodOptionsSchema).length > 0;
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* Get all registered algorithm names.
|
|
1391
|
+
* @param namespace - Optional namespace to filter by
|
|
1392
|
+
* @returns Array of algorithm names in "namespace:type" format
|
|
1393
|
+
*/
|
|
1394
|
+
static getRegisteredAlgorithms(t) {
|
|
1395
|
+
const n = [];
|
|
1396
|
+
for (const r of V.keys())
|
|
1397
|
+
(!t || r.startsWith(`${t}:`)) && n.push(r);
|
|
1398
|
+
return n.sort();
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Get all registered algorithm types.
|
|
1402
|
+
* This method is provided for API consistency with DataSource.
|
|
1403
|
+
* @returns Array of algorithm keys in "namespace:type" format
|
|
1404
|
+
* @since 1.5.0
|
|
1405
|
+
* @example
|
|
1406
|
+
* ```typescript
|
|
1407
|
+
* const types = Algorithm.getRegisteredTypes();
|
|
1408
|
+
* console.log('Available algorithms:', types);
|
|
1409
|
+
* // ['graphty:betweenness', 'graphty:closeness', 'graphty:degree', ...]
|
|
1410
|
+
* ```
|
|
1411
|
+
*/
|
|
1412
|
+
static getRegisteredTypes() {
|
|
1413
|
+
return this.getRegisteredAlgorithms();
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
Ge.optionsSchema = {};
|
|
1417
|
+
let Se = Ge;
|
|
1418
|
+
const ot = 3, Yn = 0.1;
|
|
1419
|
+
function m(e, t) {
|
|
1420
|
+
return Number.isInteger(e) ? e.toLocaleString(t) : Number(e.toFixed(ot)).toLocaleString(t, { maximumFractionDigits: ot });
|
|
1421
|
+
}
|
|
1422
|
+
function qn(e, t, n) {
|
|
1423
|
+
const r = e.fields.find((s) => s.name === t);
|
|
1424
|
+
return r === void 0 ? t : n === "technical" ? r.technicalName : r.plainName.toLowerCase();
|
|
1425
|
+
}
|
|
1426
|
+
function ue(e, t, n) {
|
|
1427
|
+
const r = e.fields.find((s) => s.name === t)?.unit;
|
|
1428
|
+
return r === void 0 ? "" : n === 1 && r.endsWith("s") ? ` ${r.slice(0, -1)}` : ` ${r}`;
|
|
1429
|
+
}
|
|
1430
|
+
function H(e, t) {
|
|
1431
|
+
const n = e.graph[t];
|
|
1432
|
+
return typeof n == "number" && Number.isFinite(n) ? n : void 0;
|
|
1433
|
+
}
|
|
1434
|
+
function Kn(e) {
|
|
1435
|
+
return e[0];
|
|
1436
|
+
}
|
|
1437
|
+
function Zn(e, t, n) {
|
|
1438
|
+
const { locale: r, audience: s } = n, o = qn(e, "value", s), i = Kn(t.top);
|
|
1439
|
+
if (i === void 0 || t.median === null)
|
|
1440
|
+
return `Nothing was measured, so there is no ${o} to report.`;
|
|
1441
|
+
const a = [
|
|
1442
|
+
`${i.label} has the highest ${o}, at ${m(i.value, r)}${ue(e, "value", i.value)}.`,
|
|
1443
|
+
`The typical element sits at ${m(t.median, r)}${ue(e, "value", t.median)}.`
|
|
1444
|
+
];
|
|
1445
|
+
return t.measured > 0 && t.tiedAtMin / t.measured >= Yn && t.min !== null && a.push(
|
|
1446
|
+
`${m(t.tiedAtMin, r)} of ${m(t.measured, r)} sit at the lowest value, ${m(t.min, r)}${ue(e, "value", t.min)}.`
|
|
1447
|
+
), t.count > t.measured && a.push(`${m(t.count - t.measured, r)} were not measured.`), a.join(" ");
|
|
1448
|
+
}
|
|
1449
|
+
function Xn(e, t, n) {
|
|
1450
|
+
const { locale: r } = n, s = t.groups ?? [];
|
|
1451
|
+
if (s.length === 0)
|
|
1452
|
+
return "Nothing was grouped, so there are no groups to report.";
|
|
1453
|
+
const o = s[0], i = [
|
|
1454
|
+
`${m(s.length, r)} ${s.length === 1 ? "group" : "groups"} were found,`,
|
|
1455
|
+
`the largest holding ${m(o.size, r)} of ${m(t.measured, r)}.`
|
|
1456
|
+
], a = H(e, "modularity");
|
|
1457
|
+
return a !== void 0 && i.push(`Modularity is ${m(a, r)}.`), i.join(" ");
|
|
1458
|
+
}
|
|
1459
|
+
function Qn(e, t) {
|
|
1460
|
+
const { locale: n } = t, r = H(e, "hops"), s = H(e, "cost");
|
|
1461
|
+
if (r === void 0 && s === void 0)
|
|
1462
|
+
return "No route was found.";
|
|
1463
|
+
const o = [];
|
|
1464
|
+
return r !== void 0 && o.push(`The route runs ${m(r, n)} ${r === 1 ? "hop" : "hops"}.`), s !== void 0 && o.push(`Its total cost is ${m(s, n)}.`), o.join(" ");
|
|
1465
|
+
}
|
|
1466
|
+
function er(e, t, n) {
|
|
1467
|
+
const { locale: r } = n, s = H(e, "count") ?? t.measured, o = e.shape === "edge-set" ? "edge" : "node";
|
|
1468
|
+
return s === 0 ? `No ${o}s were selected.` : `${m(s, r)} ${s === 1 ? o : `${o}s`} were selected.`;
|
|
1469
|
+
}
|
|
1470
|
+
function tr(e, t) {
|
|
1471
|
+
const { pairs: n } = e.graph, r = Array.isArray(n) ? n.length : 0;
|
|
1472
|
+
return r === 0 ? "No pairs were found." : `${m(r, t.locale)} ${r === 1 ? "pair was" : "pairs were"} found.`;
|
|
1473
|
+
}
|
|
1474
|
+
function nr(e, t) {
|
|
1475
|
+
const n = H(e, "steps");
|
|
1476
|
+
return n === void 0 || n === 0 ? "The series is empty." : `The series covers ${m(n, t.locale)} ${n === 1 ? "step" : "steps"}.`;
|
|
1477
|
+
}
|
|
1478
|
+
function it(e, t) {
|
|
1479
|
+
return e.measured === 0 ? "The run produced no values." : `The run covered ${m(e.measured, t.locale)} of ${m(e.count, t.locale)}.`;
|
|
1480
|
+
}
|
|
1481
|
+
function rr(e, t) {
|
|
1482
|
+
const n = e.summary(), { shape: r } = e;
|
|
1483
|
+
switch (r) {
|
|
1484
|
+
case "node-metric":
|
|
1485
|
+
case "edge-metric":
|
|
1486
|
+
return Zn(e, n, t);
|
|
1487
|
+
case "community":
|
|
1488
|
+
case "layered-grouping":
|
|
1489
|
+
case "category-table":
|
|
1490
|
+
return Xn(e, n, t);
|
|
1491
|
+
case "path":
|
|
1492
|
+
return Qn(e, t);
|
|
1493
|
+
case "node-set":
|
|
1494
|
+
case "edge-set":
|
|
1495
|
+
return er(e, n, t);
|
|
1496
|
+
case "pair-list":
|
|
1497
|
+
return tr(e, t);
|
|
1498
|
+
case "temporal":
|
|
1499
|
+
return nr(e, t);
|
|
1500
|
+
case "fact":
|
|
1501
|
+
return it(n, t);
|
|
1502
|
+
default:
|
|
1503
|
+
return it(n, t);
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
function eo(e, t) {
|
|
1507
|
+
const n = t === "node", r = n ? e.nodeValue : e.edgeValue, s = n ? e.nodeHas : e.edgeHas, o = n ? e.nodeIdOf : e.edgeIdOf;
|
|
1508
|
+
return {
|
|
1509
|
+
value: r,
|
|
1510
|
+
has: s ?? ((i, a) => sr(r(i, a))),
|
|
1511
|
+
idOf: o ?? null
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
function sr(e) {
|
|
1515
|
+
return e != null;
|
|
1516
|
+
}
|
|
1517
|
+
function W(e) {
|
|
1518
|
+
return e == null || e === !1 || e === "" ? !1 : Array.isArray(e) ? e.length > 0 : typeof e == "object" ? Object.keys(e).length > 0 : !0;
|
|
1519
|
+
}
|
|
1520
|
+
function Ne(e, t) {
|
|
1521
|
+
if (e === t)
|
|
1522
|
+
return !0;
|
|
1523
|
+
if (Array.isArray(e) && Array.isArray(t))
|
|
1524
|
+
return e.length === t.length && e.every((n, r) => Ne(n, t[r]));
|
|
1525
|
+
if (at(e) && at(t)) {
|
|
1526
|
+
const n = Object.keys(e);
|
|
1527
|
+
return n.length === Object.keys(t).length && n.every((r) => Ne(e[r], t[r]));
|
|
1528
|
+
}
|
|
1529
|
+
return !1;
|
|
1530
|
+
}
|
|
1531
|
+
function at(e) {
|
|
1532
|
+
return typeof e == "object" && e !== null && !Array.isArray(e);
|
|
1533
|
+
}
|
|
1534
|
+
function y(e, t, n, r = {}) {
|
|
1535
|
+
return new g({
|
|
1536
|
+
code: "E_BAD_SELECTOR",
|
|
1537
|
+
message: `${e} (at character ${String(n)} of ${JSON.stringify(t)})`,
|
|
1538
|
+
source: "style",
|
|
1539
|
+
details: { ...r, position: n, where: t }
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
const or = Object.freeze({
|
|
1543
|
+
"[": "index, slice, wildcard and filter expressions",
|
|
1544
|
+
"]": "index, slice, wildcard and filter expressions",
|
|
1545
|
+
"{": "multi-select hashes",
|
|
1546
|
+
"}": "multi-select hashes",
|
|
1547
|
+
",": "multi-select lists",
|
|
1548
|
+
"*": "wildcards",
|
|
1549
|
+
"@": "the current-node reference",
|
|
1550
|
+
":": "slices"
|
|
1551
|
+
}), ir = ["&&", "||", "==", "!=", "<=", ">=", "!", "<", ">", ".", "(", ")"];
|
|
1552
|
+
function Ft(e) {
|
|
1553
|
+
return /[A-Za-z_]/.test(e);
|
|
1554
|
+
}
|
|
1555
|
+
function xt(e) {
|
|
1556
|
+
return /[A-Za-z0-9_]/.test(e);
|
|
1557
|
+
}
|
|
1558
|
+
function de(e, t, n) {
|
|
1559
|
+
for (let r = t + 1; r < e.length; r++) {
|
|
1560
|
+
if (e[r] === "\\") {
|
|
1561
|
+
r++;
|
|
1562
|
+
continue;
|
|
1563
|
+
}
|
|
1564
|
+
if (e[r] === n)
|
|
1565
|
+
return r;
|
|
1566
|
+
}
|
|
1567
|
+
throw y(`A ${n} is opened and never closed`, e, t, { delimiter: n });
|
|
1568
|
+
}
|
|
1569
|
+
function ar(e) {
|
|
1570
|
+
let t = "";
|
|
1571
|
+
for (let n = 0; n < e.length; n++) {
|
|
1572
|
+
if (e[n] === "\\" && (e[n + 1] === "'" || e[n + 1] === "\\")) {
|
|
1573
|
+
t += e[n + 1], n++;
|
|
1574
|
+
continue;
|
|
1575
|
+
}
|
|
1576
|
+
t += e[n];
|
|
1577
|
+
}
|
|
1578
|
+
return t;
|
|
1579
|
+
}
|
|
1580
|
+
function cr(e, t, n) {
|
|
1581
|
+
const r = n.replace(/\\`/g, "`");
|
|
1582
|
+
try {
|
|
1583
|
+
return JSON.parse(r);
|
|
1584
|
+
} catch {
|
|
1585
|
+
throw y(
|
|
1586
|
+
`A literal between backticks must be JSON, so a bare word needs quotes: write \`"${r}"\` rather than \`${r}\``,
|
|
1587
|
+
e,
|
|
1588
|
+
t,
|
|
1589
|
+
{ literal: r }
|
|
1590
|
+
);
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
function ur(e, t, n) {
|
|
1594
|
+
try {
|
|
1595
|
+
const r = JSON.parse(n);
|
|
1596
|
+
if (typeof r == "string")
|
|
1597
|
+
return r;
|
|
1598
|
+
} catch {
|
|
1599
|
+
}
|
|
1600
|
+
throw y(`A quoted attribute name follows JSON's rules for a string, and ${n} does not`, e, t, {
|
|
1601
|
+
name: n
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
function dr(e) {
|
|
1605
|
+
const t = [];
|
|
1606
|
+
let n = 0;
|
|
1607
|
+
for (; n < e.length; ) {
|
|
1608
|
+
const r = e.charAt(n);
|
|
1609
|
+
if (/\s/.test(r)) {
|
|
1610
|
+
n++;
|
|
1611
|
+
continue;
|
|
1612
|
+
}
|
|
1613
|
+
const s = or[r];
|
|
1614
|
+
if (s !== void 0)
|
|
1615
|
+
throw y(`A selector does not support ${s}`, e, n, { construct: s });
|
|
1616
|
+
if (r === "|" && e.charAt(n + 1) !== "|")
|
|
1617
|
+
throw y("A selector does not support pipe expressions", e, n, {
|
|
1618
|
+
construct: "pipe expressions"
|
|
1619
|
+
});
|
|
1620
|
+
if (r === "&" && e.charAt(n + 1) !== "&")
|
|
1621
|
+
throw y("A selector does not support expression references", e, n, {
|
|
1622
|
+
construct: "expression references"
|
|
1623
|
+
});
|
|
1624
|
+
const o = ir.find((i) => e.startsWith(i, n));
|
|
1625
|
+
if (o !== void 0) {
|
|
1626
|
+
t.push({ kind: "operator", text: o, at: n }), n += o.length;
|
|
1627
|
+
continue;
|
|
1628
|
+
}
|
|
1629
|
+
if (r === "`") {
|
|
1630
|
+
const i = de(e, n, "`");
|
|
1631
|
+
t.push({
|
|
1632
|
+
kind: "literal",
|
|
1633
|
+
text: "",
|
|
1634
|
+
value: cr(e, n, e.slice(n + 1, i)),
|
|
1635
|
+
at: n
|
|
1636
|
+
}), n = i + 1;
|
|
1637
|
+
continue;
|
|
1638
|
+
}
|
|
1639
|
+
if (r === "'") {
|
|
1640
|
+
const i = de(e, n, "'");
|
|
1641
|
+
t.push({ kind: "literal", text: "", value: ar(e.slice(n + 1, i)), at: n }), n = i + 1;
|
|
1642
|
+
continue;
|
|
1643
|
+
}
|
|
1644
|
+
if (r === '"') {
|
|
1645
|
+
const i = de(e, n, '"');
|
|
1646
|
+
t.push({ kind: "identifier", text: ur(e, n, e.slice(n, i + 1)), at: n }), n = i + 1;
|
|
1647
|
+
continue;
|
|
1648
|
+
}
|
|
1649
|
+
if (Ft(r)) {
|
|
1650
|
+
let i = n + 1;
|
|
1651
|
+
for (; i < e.length && xt(e.charAt(i)); )
|
|
1652
|
+
i++;
|
|
1653
|
+
t.push({ kind: "identifier", text: e.slice(n, i), at: n }), n = i;
|
|
1654
|
+
continue;
|
|
1655
|
+
}
|
|
1656
|
+
throw /[0-9-]/.test(r) ? y("A number in a selector goes between backticks, so write `5` rather than 5", e, n, {
|
|
1657
|
+
character: r
|
|
1658
|
+
}) : y(`${JSON.stringify(r)} is not something a selector can contain`, e, n, {
|
|
1659
|
+
character: r
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
return t.push({ kind: "end", text: "", at: e.length }), t;
|
|
1663
|
+
}
|
|
1664
|
+
const lr = Object.freeze({
|
|
1665
|
+
"!=": "!=",
|
|
1666
|
+
"<": "<",
|
|
1667
|
+
"<=": "<=",
|
|
1668
|
+
"==": "==",
|
|
1669
|
+
">": ">",
|
|
1670
|
+
">=": ">="
|
|
1671
|
+
});
|
|
1672
|
+
function C(e) {
|
|
1673
|
+
return e.tokens[e.index];
|
|
1674
|
+
}
|
|
1675
|
+
function _(e, t) {
|
|
1676
|
+
const n = C(e);
|
|
1677
|
+
return n.kind === "operator" && n.text === t;
|
|
1678
|
+
}
|
|
1679
|
+
function fr(e) {
|
|
1680
|
+
const t = C(e), n = [];
|
|
1681
|
+
for (; ; ) {
|
|
1682
|
+
const r = C(e);
|
|
1683
|
+
if (r.kind !== "identifier")
|
|
1684
|
+
throw y("A `.` must be followed by an attribute name", e.where, r.at);
|
|
1685
|
+
if (r.text.includes("."))
|
|
1686
|
+
throw y(
|
|
1687
|
+
`A quoted attribute name may not contain a dot: ${JSON.stringify(r.text)} would be indistinguishable from two names`,
|
|
1688
|
+
e.where,
|
|
1689
|
+
r.at,
|
|
1690
|
+
{ segment: r.text }
|
|
1691
|
+
);
|
|
1692
|
+
if (e.index++, _(e, "("))
|
|
1693
|
+
throw y(
|
|
1694
|
+
`A selector does not support functions, so ${r.text}(...) cannot be called here`,
|
|
1695
|
+
e.where,
|
|
1696
|
+
r.at,
|
|
1697
|
+
{ construct: "functions", function: r.text }
|
|
1698
|
+
);
|
|
1699
|
+
if (n.push(r.text), !_(e, "."))
|
|
1700
|
+
return { kind: "path", path: n.join("."), at: t.at };
|
|
1701
|
+
e.index++;
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
function pr(e) {
|
|
1705
|
+
const t = C(e);
|
|
1706
|
+
if (t.kind === "literal")
|
|
1707
|
+
return e.index++, { kind: "literal", value: t.value };
|
|
1708
|
+
if (t.kind === "identifier")
|
|
1709
|
+
return fr(e);
|
|
1710
|
+
if (_(e, "(")) {
|
|
1711
|
+
e.index++;
|
|
1712
|
+
const n = zt(e);
|
|
1713
|
+
if (!_(e, ")"))
|
|
1714
|
+
throw y("A `(` is opened and never closed", e.where, t.at);
|
|
1715
|
+
return e.index++, { kind: "group", inner: n };
|
|
1716
|
+
}
|
|
1717
|
+
throw y(
|
|
1718
|
+
t.kind === "end" ? "The selector ends where an attribute name, a literal or a `(` should be" : `${JSON.stringify(t.text)} is where an attribute name, a literal or a \`(\` should be`,
|
|
1719
|
+
e.where,
|
|
1720
|
+
t.at
|
|
1721
|
+
);
|
|
1722
|
+
}
|
|
1723
|
+
function Ee(e) {
|
|
1724
|
+
if (!_(e, "!"))
|
|
1725
|
+
return pr(e);
|
|
1726
|
+
const t = C(e);
|
|
1727
|
+
e.index++;
|
|
1728
|
+
const n = Ee(e);
|
|
1729
|
+
if (n.kind === "path" && n.path.includes("."))
|
|
1730
|
+
throw y(
|
|
1731
|
+
`In JMESPath \`!\` binds tighter than \`.\`, so !${n.path} means (!${n.path.split(".")[0]})${n.path.slice(n.path.indexOf("."))} rather than the opposite of ${n.path}. Write !(${n.path}) for that`,
|
|
1732
|
+
e.where,
|
|
1733
|
+
t.at,
|
|
1734
|
+
{ path: n.path }
|
|
1735
|
+
);
|
|
1736
|
+
return { kind: "not", operand: n };
|
|
1737
|
+
}
|
|
1738
|
+
function ct(e) {
|
|
1739
|
+
const t = Ee(e), n = C(e), r = n.kind === "operator" ? lr[n.text] : void 0;
|
|
1740
|
+
return r === void 0 ? t : (e.index++, { kind: "compare", operator: r, left: t, right: Ee(e) });
|
|
1741
|
+
}
|
|
1742
|
+
function ut(e) {
|
|
1743
|
+
let t = ct(e);
|
|
1744
|
+
for (; _(e, "&&"); )
|
|
1745
|
+
e.index++, t = { kind: "and", left: t, right: ct(e) };
|
|
1746
|
+
return t;
|
|
1747
|
+
}
|
|
1748
|
+
function zt(e) {
|
|
1749
|
+
let t = ut(e);
|
|
1750
|
+
for (; _(e, "||"); )
|
|
1751
|
+
e.index++, t = { kind: "or", left: t, right: ut(e) };
|
|
1752
|
+
return t;
|
|
1753
|
+
}
|
|
1754
|
+
function hr(e) {
|
|
1755
|
+
const t = { where: e, tokens: dr(e), index: 0 }, n = zt(t), r = C(t);
|
|
1756
|
+
if (r.kind !== "end")
|
|
1757
|
+
throw y(
|
|
1758
|
+
`${JSON.stringify(r.text)} is left over at the end of the selector`,
|
|
1759
|
+
e,
|
|
1760
|
+
r.at
|
|
1761
|
+
);
|
|
1762
|
+
return n;
|
|
1763
|
+
}
|
|
1764
|
+
function P(e, t) {
|
|
1765
|
+
switch (e.kind) {
|
|
1766
|
+
case "path":
|
|
1767
|
+
t.includes(e.path) || t.push(e.path);
|
|
1768
|
+
return;
|
|
1769
|
+
case "group":
|
|
1770
|
+
P(e.inner, t);
|
|
1771
|
+
return;
|
|
1772
|
+
case "not":
|
|
1773
|
+
P(e.operand, t);
|
|
1774
|
+
return;
|
|
1775
|
+
case "and":
|
|
1776
|
+
case "or":
|
|
1777
|
+
case "compare":
|
|
1778
|
+
P(e.left, t), P(e.right, t);
|
|
1779
|
+
return;
|
|
1780
|
+
default:
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
function k(e, t) {
|
|
1785
|
+
switch (e.kind) {
|
|
1786
|
+
case "path": {
|
|
1787
|
+
const { path: n } = e, { value: r } = t;
|
|
1788
|
+
return (s) => {
|
|
1789
|
+
const o = r(s, n);
|
|
1790
|
+
return o === void 0 ? null : o;
|
|
1791
|
+
};
|
|
1792
|
+
}
|
|
1793
|
+
case "literal": {
|
|
1794
|
+
const { value: n } = e;
|
|
1795
|
+
return () => n;
|
|
1796
|
+
}
|
|
1797
|
+
case "group":
|
|
1798
|
+
return k(e.inner, t);
|
|
1799
|
+
case "not": {
|
|
1800
|
+
const n = k(e.operand, t);
|
|
1801
|
+
return (r) => !W(n(r));
|
|
1802
|
+
}
|
|
1803
|
+
case "and": {
|
|
1804
|
+
const n = k(e.left, t), r = k(e.right, t);
|
|
1805
|
+
return (s) => {
|
|
1806
|
+
const o = n(s);
|
|
1807
|
+
return W(o) ? r(s) : o;
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1810
|
+
case "or": {
|
|
1811
|
+
const n = k(e.left, t), r = k(e.right, t);
|
|
1812
|
+
return (s) => {
|
|
1813
|
+
const o = n(s);
|
|
1814
|
+
return W(o) ? o : r(s);
|
|
1815
|
+
};
|
|
1816
|
+
}
|
|
1817
|
+
default:
|
|
1818
|
+
return yr(e.operator, e.left, e.right, t);
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
const gr = Object.freeze({
|
|
1822
|
+
"<": (e, t) => e < t,
|
|
1823
|
+
"<=": (e, t) => e <= t,
|
|
1824
|
+
">": (e, t) => e > t,
|
|
1825
|
+
">=": (e, t) => e >= t
|
|
1826
|
+
});
|
|
1827
|
+
function mr(e, t) {
|
|
1828
|
+
return e.kind === "literal" ? e : t.kind === "literal" ? t : null;
|
|
1829
|
+
}
|
|
1830
|
+
function yr(e, t, n, r) {
|
|
1831
|
+
if (e === "==" || e === "!=") {
|
|
1832
|
+
const a = e === "==", c = t.kind === "literal", u = mr(t, n), f = c ? n : t;
|
|
1833
|
+
if (u !== null && u.value === null && f.kind === "path") {
|
|
1834
|
+
const { path: p } = f, { has: w } = r;
|
|
1835
|
+
return (h) => w(h, p) !== a;
|
|
1836
|
+
}
|
|
1837
|
+
const l = k(t, r), d = k(n, r);
|
|
1838
|
+
if (u !== null && u.value !== null && typeof u.value != "object") {
|
|
1839
|
+
const { value: p } = u, w = c ? d : l;
|
|
1840
|
+
return (h) => w(h) === p === a;
|
|
1841
|
+
}
|
|
1842
|
+
return (p) => Ne(l(p), d(p)) === a;
|
|
1843
|
+
}
|
|
1844
|
+
const s = k(t, r), o = k(n, r), i = gr[e];
|
|
1845
|
+
return (a) => {
|
|
1846
|
+
const c = s(a), u = o(a);
|
|
1847
|
+
return typeof c == "number" && typeof u == "number" ? i(c, u) : null;
|
|
1848
|
+
};
|
|
1849
|
+
}
|
|
1850
|
+
function T(e, t) {
|
|
1851
|
+
switch (e.kind) {
|
|
1852
|
+
case "compare":
|
|
1853
|
+
case "not": {
|
|
1854
|
+
const n = k(e, t);
|
|
1855
|
+
return (r) => n(r) === !0;
|
|
1856
|
+
}
|
|
1857
|
+
case "group":
|
|
1858
|
+
return T(e.inner, t);
|
|
1859
|
+
case "and": {
|
|
1860
|
+
const n = T(e.left, t), r = T(e.right, t);
|
|
1861
|
+
return (s) => n(s) && r(s);
|
|
1862
|
+
}
|
|
1863
|
+
case "or": {
|
|
1864
|
+
const n = T(e.left, t), r = T(e.right, t);
|
|
1865
|
+
return (s) => n(s) || r(s);
|
|
1866
|
+
}
|
|
1867
|
+
default: {
|
|
1868
|
+
const n = k(e, t);
|
|
1869
|
+
return (r) => W(n(r));
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
function br(e) {
|
|
1874
|
+
return e.split(".").map((t) => wr(t) ? t : JSON.stringify(t)).join(".");
|
|
1875
|
+
}
|
|
1876
|
+
function wr(e) {
|
|
1877
|
+
if (e === "" || !Ft(e[0]))
|
|
1878
|
+
return !1;
|
|
1879
|
+
for (let t = 1; t < e.length; t++)
|
|
1880
|
+
if (!xt(e[t]))
|
|
1881
|
+
return !1;
|
|
1882
|
+
return !0;
|
|
1883
|
+
}
|
|
1884
|
+
function to(e, t) {
|
|
1885
|
+
const { has: n } = e;
|
|
1886
|
+
return (r) => n(r, t);
|
|
1887
|
+
}
|
|
1888
|
+
function no(e, t) {
|
|
1889
|
+
const { idOf: n } = e;
|
|
1890
|
+
if (n === null)
|
|
1891
|
+
throw new g({
|
|
1892
|
+
code: "E_UNSUPPORTED",
|
|
1893
|
+
message: 'This session cannot evaluate an "ids" selector, because it cannot say which id sits at which row. Painting the layer anyway would colour elements it never named.',
|
|
1894
|
+
source: "style",
|
|
1895
|
+
details: { match: "ids" }
|
|
1896
|
+
});
|
|
1897
|
+
return (r) => t.has(n(r));
|
|
1898
|
+
}
|
|
1899
|
+
function ro(e, t, n) {
|
|
1900
|
+
const { value: r } = e;
|
|
1901
|
+
return (s) => {
|
|
1902
|
+
const o = n();
|
|
1903
|
+
if (o === void 0)
|
|
1904
|
+
return !1;
|
|
1905
|
+
const i = r(s, t);
|
|
1906
|
+
return typeof i == "number" && Number.isFinite(i) && i >= o;
|
|
1907
|
+
};
|
|
1908
|
+
}
|
|
1909
|
+
function so(e, t) {
|
|
1910
|
+
return (n) => {
|
|
1911
|
+
const r = e.bits(t);
|
|
1912
|
+
return r !== null && oe(r, n);
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
function oo(e, t) {
|
|
1916
|
+
const n = hr(e), r = [];
|
|
1917
|
+
if (P(n, r), r.length === 0) {
|
|
1918
|
+
let s = n;
|
|
1919
|
+
for (; s.kind === "group"; )
|
|
1920
|
+
s = s.inner;
|
|
1921
|
+
const o = s.kind === "literal" && typeof s.value == "string";
|
|
1922
|
+
throw y(
|
|
1923
|
+
o ? "The selector is a quoted string literal, which is always true, so it would match every element. Remove the outer quotes so it is read as an expression" : 'The selector reads no attribute of the element, so it answers the same for every element. Write { match: "everything" } for a layer that really is meant to paint the whole graph',
|
|
1924
|
+
e,
|
|
1925
|
+
0,
|
|
1926
|
+
{ constant: !0 }
|
|
1927
|
+
);
|
|
1928
|
+
}
|
|
1929
|
+
return { paths: Object.freeze(r), test: T(n, t) };
|
|
1930
|
+
}
|
|
1931
|
+
const Ie = "results", vr = "$";
|
|
1932
|
+
function Y(e, t) {
|
|
1933
|
+
return t === void 0 ? `${Ie}.${e}` : `${Ie}.${e}.${t}`;
|
|
1934
|
+
}
|
|
1935
|
+
function Or(e) {
|
|
1936
|
+
return `Group ${String(e)}`;
|
|
1937
|
+
}
|
|
1938
|
+
function Lt(e, t) {
|
|
1939
|
+
const n = Number(e), r = Number(t);
|
|
1940
|
+
return Number.isFinite(n) && Number.isFinite(r) && String(n) === String(e) && String(r) === String(t) ? n - r : String(e).localeCompare(String(t));
|
|
1941
|
+
}
|
|
1942
|
+
const jt = {
|
|
1943
|
+
// -- per element ---------------------------------------------------------------------
|
|
1944
|
+
value: {
|
|
1945
|
+
meaning: "The number this metric measured for this element.",
|
|
1946
|
+
scope: "element",
|
|
1947
|
+
types: ["number", "integer"]
|
|
1948
|
+
},
|
|
1949
|
+
rank: {
|
|
1950
|
+
meaning: "Where this element sits when every measured element is ordered best first, starting at 1.",
|
|
1951
|
+
scope: "element",
|
|
1952
|
+
types: ["integer"]
|
|
1953
|
+
},
|
|
1954
|
+
percentile: {
|
|
1955
|
+
meaning: "The share of measured elements this one ranks at or above, from 0 to 1.",
|
|
1956
|
+
scope: "element",
|
|
1957
|
+
types: ["number"]
|
|
1958
|
+
},
|
|
1959
|
+
group: {
|
|
1960
|
+
meaning: "Which group this node was placed in.",
|
|
1961
|
+
scope: "element",
|
|
1962
|
+
types: ["integer", "string"]
|
|
1963
|
+
},
|
|
1964
|
+
groupSize: {
|
|
1965
|
+
meaning: "How many nodes share this node's group.",
|
|
1966
|
+
scope: "element",
|
|
1967
|
+
types: ["integer"]
|
|
1968
|
+
},
|
|
1969
|
+
level: {
|
|
1970
|
+
meaning: "How many levels out from the start this node sits, counting the start as 0.",
|
|
1971
|
+
scope: "element",
|
|
1972
|
+
types: ["integer"]
|
|
1973
|
+
},
|
|
1974
|
+
levelSize: {
|
|
1975
|
+
meaning: "How many nodes share this node's level.",
|
|
1976
|
+
scope: "element",
|
|
1977
|
+
types: ["integer"]
|
|
1978
|
+
},
|
|
1979
|
+
category: {
|
|
1980
|
+
meaning: "The category this node was sorted into.",
|
|
1981
|
+
scope: "element",
|
|
1982
|
+
types: ["string"]
|
|
1983
|
+
},
|
|
1984
|
+
score: {
|
|
1985
|
+
meaning: "How strongly this node belongs to its category.",
|
|
1986
|
+
scope: "element",
|
|
1987
|
+
types: ["number"]
|
|
1988
|
+
},
|
|
1989
|
+
onPath: {
|
|
1990
|
+
meaning: "Whether this element is on the route the run found.",
|
|
1991
|
+
scope: "element",
|
|
1992
|
+
types: ["boolean"]
|
|
1993
|
+
},
|
|
1994
|
+
order: {
|
|
1995
|
+
meaning: "This node's position along the route, counting the source as 0.",
|
|
1996
|
+
scope: "element",
|
|
1997
|
+
types: ["integer"]
|
|
1998
|
+
},
|
|
1999
|
+
in: {
|
|
2000
|
+
meaning: "Whether this element is in the set the run selected.",
|
|
2001
|
+
scope: "element",
|
|
2002
|
+
types: ["boolean"]
|
|
2003
|
+
},
|
|
2004
|
+
// -- per graph -----------------------------------------------------------------------
|
|
2005
|
+
min: {
|
|
2006
|
+
meaning: "The lowest value any measured element carries.",
|
|
2007
|
+
scope: "graph",
|
|
2008
|
+
types: ["number"]
|
|
2009
|
+
},
|
|
2010
|
+
max: {
|
|
2011
|
+
meaning: "The highest value any measured element carries.",
|
|
2012
|
+
scope: "graph",
|
|
2013
|
+
types: ["number"]
|
|
2014
|
+
},
|
|
2015
|
+
median: {
|
|
2016
|
+
meaning: "The middle value once the measured elements are ordered.",
|
|
2017
|
+
scope: "graph",
|
|
2018
|
+
types: ["number"]
|
|
2019
|
+
},
|
|
2020
|
+
mean: {
|
|
2021
|
+
meaning: "The average value across the measured elements.",
|
|
2022
|
+
scope: "graph",
|
|
2023
|
+
types: ["number"]
|
|
2024
|
+
},
|
|
2025
|
+
measured: {
|
|
2026
|
+
meaning: "How many elements the run produced a value for. Smaller than the scope when some elements have nothing to measure. Distinct from RunResult.measured, which counts the nodes and edges the run looked at.",
|
|
2027
|
+
scope: "graph",
|
|
2028
|
+
types: ["integer"]
|
|
2029
|
+
},
|
|
2030
|
+
normalization: {
|
|
2031
|
+
meaning: 'How the values were scaled before publication: "max", "min-max" or "none".',
|
|
2032
|
+
scope: "graph",
|
|
2033
|
+
types: ["string"]
|
|
2034
|
+
},
|
|
2035
|
+
tiedAtMin: {
|
|
2036
|
+
meaning: "How many measured elements sit at the lowest value, which is what says whether a colour ramp is about to paint most of the graph one colour.",
|
|
2037
|
+
scope: "graph",
|
|
2038
|
+
types: ["integer"]
|
|
2039
|
+
},
|
|
2040
|
+
groupCount: {
|
|
2041
|
+
meaning: "How many groups the partition has.",
|
|
2042
|
+
scope: "graph",
|
|
2043
|
+
types: ["integer"]
|
|
2044
|
+
},
|
|
2045
|
+
modularity: {
|
|
2046
|
+
meaning: "How much better this partition is than a random one, from -0.5 to 1.",
|
|
2047
|
+
scope: "graph",
|
|
2048
|
+
types: ["number"]
|
|
2049
|
+
},
|
|
2050
|
+
sizes: {
|
|
2051
|
+
meaning: "The size of each group or level, largest first.",
|
|
2052
|
+
scope: "graph",
|
|
2053
|
+
types: ["table"]
|
|
2054
|
+
},
|
|
2055
|
+
levelCount: {
|
|
2056
|
+
meaning: "How many levels the walk reached.",
|
|
2057
|
+
scope: "graph",
|
|
2058
|
+
types: ["integer"]
|
|
2059
|
+
},
|
|
2060
|
+
categories: {
|
|
2061
|
+
meaning: "One row per category, with its name and how many elements fell into it.",
|
|
2062
|
+
scope: "graph",
|
|
2063
|
+
types: ["table"]
|
|
2064
|
+
},
|
|
2065
|
+
length: {
|
|
2066
|
+
meaning: "How many nodes are on the route.",
|
|
2067
|
+
scope: "graph",
|
|
2068
|
+
types: ["integer"]
|
|
2069
|
+
},
|
|
2070
|
+
cost: {
|
|
2071
|
+
meaning: "What the route costs in total, summing the weight of every edge on it.",
|
|
2072
|
+
scope: "graph",
|
|
2073
|
+
types: ["number"]
|
|
2074
|
+
},
|
|
2075
|
+
hops: {
|
|
2076
|
+
meaning: "How many edges are on the route.",
|
|
2077
|
+
scope: "graph",
|
|
2078
|
+
types: ["integer"]
|
|
2079
|
+
},
|
|
2080
|
+
count: {
|
|
2081
|
+
meaning: "How many elements are in the set.",
|
|
2082
|
+
scope: "graph",
|
|
2083
|
+
types: ["integer"]
|
|
2084
|
+
},
|
|
2085
|
+
pairs: {
|
|
2086
|
+
meaning: "One row per scored pair of elements, best first.",
|
|
2087
|
+
scope: "graph",
|
|
2088
|
+
types: ["table"]
|
|
2089
|
+
},
|
|
2090
|
+
steps: {
|
|
2091
|
+
meaning: "One row per time step, with the step's window and what was visible in it.",
|
|
2092
|
+
scope: "graph",
|
|
2093
|
+
types: ["table"]
|
|
2094
|
+
},
|
|
2095
|
+
series: {
|
|
2096
|
+
meaning: "One row per tracked quantity, carrying its value at every step.",
|
|
2097
|
+
scope: "graph",
|
|
2098
|
+
types: ["table"]
|
|
2099
|
+
},
|
|
2100
|
+
rates: {
|
|
2101
|
+
meaning: "One row per tracked quantity, carrying how fast it changed between steps.",
|
|
2102
|
+
scope: "graph",
|
|
2103
|
+
types: ["table"]
|
|
2104
|
+
},
|
|
2105
|
+
changeThreshold: {
|
|
2106
|
+
meaning: "The rate of change above which a step counts as a change rather than drift.",
|
|
2107
|
+
scope: "graph",
|
|
2108
|
+
types: ["number"]
|
|
2109
|
+
}
|
|
2110
|
+
}, io = Object.keys(jt), je = {
|
|
2111
|
+
"node-metric": {
|
|
2112
|
+
shape: "node-metric",
|
|
2113
|
+
primaryField: "value",
|
|
2114
|
+
nodeFields: ["value", "rank", "percentile"],
|
|
2115
|
+
edgeFields: [],
|
|
2116
|
+
graphFields: ["min", "max", "median", "mean", "measured", "normalization", "tiedAtMin"],
|
|
2117
|
+
optionalGraphFields: [],
|
|
2118
|
+
headlineScalar: !1,
|
|
2119
|
+
layer: "encoding"
|
|
2120
|
+
},
|
|
2121
|
+
"edge-metric": {
|
|
2122
|
+
shape: "edge-metric",
|
|
2123
|
+
primaryField: "value",
|
|
2124
|
+
nodeFields: [],
|
|
2125
|
+
edgeFields: ["value", "rank", "percentile"],
|
|
2126
|
+
graphFields: ["min", "max", "median", "mean", "measured", "normalization", "tiedAtMin"],
|
|
2127
|
+
optionalGraphFields: [],
|
|
2128
|
+
headlineScalar: !1,
|
|
2129
|
+
layer: "encoding"
|
|
2130
|
+
},
|
|
2131
|
+
community: {
|
|
2132
|
+
shape: "community",
|
|
2133
|
+
primaryField: "group",
|
|
2134
|
+
nodeFields: ["group", "groupSize"],
|
|
2135
|
+
edgeFields: [],
|
|
2136
|
+
graphFields: ["groupCount", "sizes"],
|
|
2137
|
+
// Only an algorithm that scores its own partition can publish modularity. Label
|
|
2138
|
+
// propagation and connected components do not, and a required field they cannot fill
|
|
2139
|
+
// would be a number invented to satisfy a table.
|
|
2140
|
+
optionalGraphFields: ["modularity"],
|
|
2141
|
+
headlineScalar: !1,
|
|
2142
|
+
layer: "encoding"
|
|
2143
|
+
},
|
|
2144
|
+
"layered-grouping": {
|
|
2145
|
+
shape: "layered-grouping",
|
|
2146
|
+
primaryField: "level",
|
|
2147
|
+
nodeFields: ["level", "levelSize"],
|
|
2148
|
+
edgeFields: [],
|
|
2149
|
+
graphFields: ["levelCount", "sizes"],
|
|
2150
|
+
optionalGraphFields: [],
|
|
2151
|
+
headlineScalar: !1,
|
|
2152
|
+
layer: "encoding"
|
|
2153
|
+
},
|
|
2154
|
+
"category-table": {
|
|
2155
|
+
shape: "category-table",
|
|
2156
|
+
primaryField: "category",
|
|
2157
|
+
nodeFields: ["category", "score", "rank"],
|
|
2158
|
+
edgeFields: [],
|
|
2159
|
+
graphFields: ["categories"],
|
|
2160
|
+
optionalGraphFields: [],
|
|
2161
|
+
headlineScalar: !1,
|
|
2162
|
+
layer: "encoding"
|
|
2163
|
+
},
|
|
2164
|
+
path: {
|
|
2165
|
+
shape: "path",
|
|
2166
|
+
primaryField: "onPath",
|
|
2167
|
+
nodeFields: ["onPath", "order"],
|
|
2168
|
+
// The edges of the route carry membership but not a position: an edge's place in the
|
|
2169
|
+
// route is the order of the node it leaves.
|
|
2170
|
+
edgeFields: ["onPath"],
|
|
2171
|
+
graphFields: ["length", "cost", "hops"],
|
|
2172
|
+
optionalGraphFields: [],
|
|
2173
|
+
headlineScalar: !1,
|
|
2174
|
+
layer: "highlight"
|
|
2175
|
+
},
|
|
2176
|
+
"node-set": {
|
|
2177
|
+
shape: "node-set",
|
|
2178
|
+
primaryField: "in",
|
|
2179
|
+
nodeFields: ["in"],
|
|
2180
|
+
edgeFields: [],
|
|
2181
|
+
graphFields: ["count"],
|
|
2182
|
+
optionalGraphFields: [],
|
|
2183
|
+
headlineScalar: !0,
|
|
2184
|
+
layer: "highlight"
|
|
2185
|
+
},
|
|
2186
|
+
"edge-set": {
|
|
2187
|
+
shape: "edge-set",
|
|
2188
|
+
primaryField: "in",
|
|
2189
|
+
nodeFields: [],
|
|
2190
|
+
edgeFields: ["in"],
|
|
2191
|
+
graphFields: ["count"],
|
|
2192
|
+
optionalGraphFields: [],
|
|
2193
|
+
headlineScalar: !0,
|
|
2194
|
+
layer: "highlight"
|
|
2195
|
+
},
|
|
2196
|
+
"pair-list": {
|
|
2197
|
+
shape: "pair-list",
|
|
2198
|
+
primaryField: "pairs",
|
|
2199
|
+
nodeFields: [],
|
|
2200
|
+
edgeFields: [],
|
|
2201
|
+
graphFields: ["pairs"],
|
|
2202
|
+
optionalGraphFields: [],
|
|
2203
|
+
headlineScalar: !1,
|
|
2204
|
+
layer: "none"
|
|
2205
|
+
},
|
|
2206
|
+
temporal: {
|
|
2207
|
+
shape: "temporal",
|
|
2208
|
+
primaryField: "series",
|
|
2209
|
+
nodeFields: [],
|
|
2210
|
+
edgeFields: [],
|
|
2211
|
+
graphFields: ["steps", "series", "rates", "changeThreshold"],
|
|
2212
|
+
optionalGraphFields: [],
|
|
2213
|
+
headlineScalar: !1,
|
|
2214
|
+
layer: "none"
|
|
2215
|
+
},
|
|
2216
|
+
fact: {
|
|
2217
|
+
shape: "fact",
|
|
2218
|
+
primaryField: null,
|
|
2219
|
+
nodeFields: [],
|
|
2220
|
+
edgeFields: [],
|
|
2221
|
+
graphFields: [],
|
|
2222
|
+
optionalGraphFields: [],
|
|
2223
|
+
headlineScalar: !1,
|
|
2224
|
+
layer: "none"
|
|
2225
|
+
}
|
|
2226
|
+
};
|
|
2227
|
+
function Re(e) {
|
|
2228
|
+
return je[e];
|
|
2229
|
+
}
|
|
2230
|
+
function ao(e) {
|
|
2231
|
+
return je[e].layer === "highlight";
|
|
2232
|
+
}
|
|
2233
|
+
function co(e, t) {
|
|
2234
|
+
const n = je[e], r = [], s = [
|
|
2235
|
+
{ names: n.nodeFields, kind: "node" },
|
|
2236
|
+
{ names: n.edgeFields, kind: "edge" },
|
|
2237
|
+
{ names: n.graphFields, kind: "graph" }
|
|
2238
|
+
];
|
|
2239
|
+
for (const { names: o, kind: i } of s)
|
|
2240
|
+
for (const a of o) {
|
|
2241
|
+
const c = t.find((f) => f.name === a && f.kind === i);
|
|
2242
|
+
if (c === void 0) {
|
|
2243
|
+
r.push({
|
|
2244
|
+
field: a,
|
|
2245
|
+
kind: i,
|
|
2246
|
+
reason: `shape "${e}" requires a ${i} field named "${a}"`
|
|
2247
|
+
});
|
|
2248
|
+
continue;
|
|
2249
|
+
}
|
|
2250
|
+
const u = jt[a].types;
|
|
2251
|
+
u.includes(c.type) || r.push({
|
|
2252
|
+
field: a,
|
|
2253
|
+
kind: i,
|
|
2254
|
+
reason: `${i} field "${a}" is typed "${c.type}", not ${u.map((f) => `"${f}"`).join(" or ")}`
|
|
2255
|
+
});
|
|
2256
|
+
}
|
|
2257
|
+
return n.headlineScalar && !kr(n, t) && r.push({
|
|
2258
|
+
field: null,
|
|
2259
|
+
kind: "graph",
|
|
2260
|
+
reason: `shape "${e}" requires one graph-level scalar of its own beside "count"`
|
|
2261
|
+
}), r;
|
|
2262
|
+
}
|
|
2263
|
+
function kr(e, t) {
|
|
2264
|
+
const n = [...e.graphFields, ...e.optionalGraphFields];
|
|
2265
|
+
return t.some((r) => r.kind === "graph" && !n.includes(r.name));
|
|
2266
|
+
}
|
|
2267
|
+
const Ar = 3;
|
|
2268
|
+
function Sr(e, t) {
|
|
2269
|
+
if (e === t)
|
|
2270
|
+
return 0;
|
|
2271
|
+
const n = new Uint32Array(t.length + 1), r = new Uint32Array(t.length + 1);
|
|
2272
|
+
for (let s = 0; s <= t.length; s++)
|
|
2273
|
+
n[s] = s;
|
|
2274
|
+
for (let s = 1; s <= e.length; s++) {
|
|
2275
|
+
r[0] = s;
|
|
2276
|
+
for (let o = 1; o <= t.length; o++) {
|
|
2277
|
+
const i = n[o - 1] + (e[s - 1] === t[o - 1] ? 0 : 1);
|
|
2278
|
+
r[o] = Math.min(r[o - 1] + 1, n[o] + 1, i);
|
|
2279
|
+
}
|
|
2280
|
+
n.set(r);
|
|
2281
|
+
}
|
|
2282
|
+
return n[t.length];
|
|
2283
|
+
}
|
|
2284
|
+
function Nr(e, t, n = Ar) {
|
|
2285
|
+
const r = e.toLowerCase(), s = t.map((o) => ({
|
|
2286
|
+
candidate: o,
|
|
2287
|
+
distance: Sr(r, o.toLowerCase())
|
|
2288
|
+
}));
|
|
2289
|
+
return s.sort((o, i) => o.distance - i.distance || o.candidate.localeCompare(i.candidate)), Object.freeze(s.slice(0, Math.max(n, 0)).map((o) => o.candidate));
|
|
2290
|
+
}
|
|
2291
|
+
function Me(e) {
|
|
2292
|
+
return typeof e == "string" ? e : "runId" in e ? e.runId : e.id;
|
|
2293
|
+
}
|
|
2294
|
+
function Er(e) {
|
|
2295
|
+
return typeof e == "string" ? void 0 : e.shape;
|
|
2296
|
+
}
|
|
2297
|
+
function Ir(e, t) {
|
|
2298
|
+
return e.fields.some((n) => n.name === t) || t in e.graph;
|
|
2299
|
+
}
|
|
2300
|
+
class Rr {
|
|
2301
|
+
#e;
|
|
2302
|
+
/**
|
|
2303
|
+
* Build the API over a registry.
|
|
2304
|
+
* @param registry - Where runs are looked up.
|
|
2305
|
+
*/
|
|
2306
|
+
constructor(t) {
|
|
2307
|
+
this.#e = t;
|
|
2308
|
+
}
|
|
2309
|
+
/**
|
|
2310
|
+
* The published path of a run's field.
|
|
2311
|
+
*
|
|
2312
|
+
* With no field the path names the run's primary field -- `value` for a metric, `group` for a
|
|
2313
|
+
* partition, `onPath` for a route -- so a caller binds an encoding to a run without knowing
|
|
2314
|
+
* what that algorithm calls its number. A `fact` result has no primary field and addresses
|
|
2315
|
+
* its whole result object instead.
|
|
2316
|
+
* @param run - The run, its result, or its id.
|
|
2317
|
+
* @param field - The field name; the shape's primary field when absent.
|
|
2318
|
+
* @returns The path.
|
|
2319
|
+
*/
|
|
2320
|
+
path(t, n) {
|
|
2321
|
+
const r = Me(t);
|
|
2322
|
+
if (n !== void 0)
|
|
2323
|
+
return Y(r, n);
|
|
2324
|
+
const s = Er(t) ?? this.#e.entry(r)?.shape, o = s === void 0 ? null : Re(s).primaryField;
|
|
2325
|
+
return o === null ? Y(r) : Y(r, o);
|
|
2326
|
+
}
|
|
2327
|
+
/**
|
|
2328
|
+
* The same field, written so a selector expression can read it.
|
|
2329
|
+
*
|
|
2330
|
+
* The quoting is the whole point: a run id carries its algorithm's name, and a hyphenated
|
|
2331
|
+
* name lexes its hyphen as subtraction, so a path pasted into an expression unquoted is a
|
|
2332
|
+
* refused selector rather than a comparison. Nothing here decides WHICH field -- that is
|
|
2333
|
+
* {@link ResultsApi.path}'s job and this defers to it -- so the two can never name different
|
|
2334
|
+
* columns.
|
|
2335
|
+
* @param run - The run, its result, or its id.
|
|
2336
|
+
* @param field - The field name; the shape's primary field when absent.
|
|
2337
|
+
* @returns The path with every segment quoted that needs it.
|
|
2338
|
+
*/
|
|
2339
|
+
term(t, n) {
|
|
2340
|
+
return br(n === void 0 ? this.path(t) : this.path(t, n));
|
|
2341
|
+
}
|
|
2342
|
+
/**
|
|
2343
|
+
* One run's result.
|
|
2344
|
+
*
|
|
2345
|
+
* The answer always comes from the registry, even when the caller passed a result object: the
|
|
2346
|
+
* question is what this session holds, and a result the session never registered is not it.
|
|
2347
|
+
* @param run - The run, its result, or its id.
|
|
2348
|
+
* @returns The result, or undefined when the session holds no such run or it has not
|
|
2349
|
+
* finished.
|
|
2350
|
+
*/
|
|
2351
|
+
get(t) {
|
|
2352
|
+
return this.#e.entry(Me(t))?.result;
|
|
2353
|
+
}
|
|
2354
|
+
/**
|
|
2355
|
+
* Whether a run, or one of its fields, is available to read.
|
|
2356
|
+
* @param run - The run, its result, or its id.
|
|
2357
|
+
* @param field - The field name; asks only about the run itself when absent.
|
|
2358
|
+
* @returns True when the path would resolve.
|
|
2359
|
+
*/
|
|
2360
|
+
has(t, n) {
|
|
2361
|
+
const r = this.get(t);
|
|
2362
|
+
return r === void 0 ? !1 : n === void 0 || Ir(r, n);
|
|
2363
|
+
}
|
|
2364
|
+
/**
|
|
2365
|
+
* Every run that has published a result, as an expression editor reads them.
|
|
2366
|
+
* @returns One root per finished run, in the order the runs were started.
|
|
2367
|
+
*/
|
|
2368
|
+
get roots() {
|
|
2369
|
+
const t = [];
|
|
2370
|
+
for (const n of this.#e.entries())
|
|
2371
|
+
n.result !== void 0 && t.push(Object.freeze({ runId: n.id, label: n.label, fields: n.result.fields }));
|
|
2372
|
+
return Object.freeze(t);
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
const Dt = /* @__PURE__ */ new WeakMap();
|
|
2376
|
+
function uo(e, t) {
|
|
2377
|
+
const n = Dt.get(e)?.entry(Me(t));
|
|
2378
|
+
return n?.result === void 0 ? void 0 : n.execution;
|
|
2379
|
+
}
|
|
2380
|
+
function lo(e) {
|
|
2381
|
+
const t = new Rr(e);
|
|
2382
|
+
return Dt.set(t, e), t;
|
|
2383
|
+
}
|
|
2384
|
+
const Mr = 20, le = 100, $r = 100, Cr = Object.freeze([]), _r = Object.freeze(["max", "min-max", "none"]);
|
|
2385
|
+
function Pt(e) {
|
|
2386
|
+
return typeof e == "string" && _r.includes(e);
|
|
2387
|
+
}
|
|
2388
|
+
function fo(e) {
|
|
2389
|
+
return {
|
|
2390
|
+
length: e.length,
|
|
2391
|
+
get: (t) => e[t]
|
|
2392
|
+
};
|
|
2393
|
+
}
|
|
2394
|
+
const Tr = Object.freeze({
|
|
2395
|
+
measured: 0,
|
|
2396
|
+
min: Number.NaN,
|
|
2397
|
+
max: Number.NaN,
|
|
2398
|
+
mean: Number.NaN,
|
|
2399
|
+
median: Number.NaN,
|
|
2400
|
+
tiedAtMin: 0,
|
|
2401
|
+
smallestPositive: null
|
|
2402
|
+
});
|
|
2403
|
+
function Ht(e) {
|
|
2404
|
+
const { length: t } = e, n = new Float64Array(t);
|
|
2405
|
+
let r = 0;
|
|
2406
|
+
for (let d = 0; d < t; d++) {
|
|
2407
|
+
const p = e.get(d);
|
|
2408
|
+
Number.isFinite(p) && (n[r] = p, r++);
|
|
2409
|
+
}
|
|
2410
|
+
if (r === 0)
|
|
2411
|
+
return { length: t, ...Tr };
|
|
2412
|
+
let s = Number.POSITIVE_INFINITY, o = Number.NEGATIVE_INFINITY, i = Number.POSITIVE_INFINITY, a = 0, c = 0;
|
|
2413
|
+
for (let d = 0; d < r; d++) {
|
|
2414
|
+
const p = n[d];
|
|
2415
|
+
p < s && (s = p), p > o && (o = p), p > 0 && p < i && (i = p);
|
|
2416
|
+
const w = p - c, h = a + w;
|
|
2417
|
+
c = h - a - w, a = h;
|
|
2418
|
+
}
|
|
2419
|
+
const u = n.slice(0, r).sort(), f = u[Math.floor((r - 1) / 2)];
|
|
2420
|
+
let l = 0;
|
|
2421
|
+
for (; l < r && u[l] === s; )
|
|
2422
|
+
l++;
|
|
2423
|
+
return {
|
|
2424
|
+
length: t,
|
|
2425
|
+
measured: r,
|
|
2426
|
+
min: s,
|
|
2427
|
+
max: o,
|
|
2428
|
+
mean: a / r,
|
|
2429
|
+
median: f,
|
|
2430
|
+
tiedAtMin: l,
|
|
2431
|
+
smallestPositive: Number.isFinite(i) ? i : null
|
|
2432
|
+
};
|
|
2433
|
+
}
|
|
2434
|
+
function Ut(e) {
|
|
2435
|
+
const t = Ht(e);
|
|
2436
|
+
return { view: Object.freeze({
|
|
2437
|
+
length: e.length,
|
|
2438
|
+
get: (r) => e.get(r),
|
|
2439
|
+
min: t.min,
|
|
2440
|
+
max: t.max,
|
|
2441
|
+
mean: t.mean,
|
|
2442
|
+
median: t.median
|
|
2443
|
+
}), statistics: t };
|
|
2444
|
+
}
|
|
2445
|
+
function De(e) {
|
|
2446
|
+
const t = e.filter((i) => Number.isFinite(i.value)).map((i) => ({ entry: i, label: String(i.id) }));
|
|
2447
|
+
t.sort((i, a) => i.entry.value !== a.entry.value ? a.entry.value - i.entry.value : i.label === a.label ? 0 : i.label < a.label ? -1 : 1);
|
|
2448
|
+
const n = t.length, r = [];
|
|
2449
|
+
let s = 0, o = Number.NaN;
|
|
2450
|
+
for (let i = 0; i < n; i++) {
|
|
2451
|
+
const { entry: a } = t[i];
|
|
2452
|
+
a.value !== o && (s = i + 1, o = a.value), r.push(
|
|
2453
|
+
Object.freeze({
|
|
2454
|
+
id: a.id,
|
|
2455
|
+
value: a.value,
|
|
2456
|
+
rank: s,
|
|
2457
|
+
percentile: (n - s + 1) / n
|
|
2458
|
+
})
|
|
2459
|
+
);
|
|
2460
|
+
}
|
|
2461
|
+
return Object.freeze(r);
|
|
2462
|
+
}
|
|
2463
|
+
function Fr(e, t) {
|
|
2464
|
+
let n = Math.min(t, e.length);
|
|
2465
|
+
for (; n > 0 && n < e.length && e[n].rank === e[n - 1].rank; )
|
|
2466
|
+
n--;
|
|
2467
|
+
if (n === e.length || n === t)
|
|
2468
|
+
return Object.freeze({ entries: e.slice(0, n), leftOut: null, reason: null });
|
|
2469
|
+
const { value: r } = e[n];
|
|
2470
|
+
let s = n;
|
|
2471
|
+
for (; s < e.length && e[s].value === r; )
|
|
2472
|
+
s++;
|
|
2473
|
+
const o = s - n, i = `${String(o)} tie at ${String(r)}, and taking them would make ${String(n + o)}, more than the ${String(t)} asked for, so ${n === 0 ? "none are" : `only the top ${String(n)} are`} taken.`;
|
|
2474
|
+
return Object.freeze({
|
|
2475
|
+
entries: e.slice(0, n),
|
|
2476
|
+
leftOut: Object.freeze({ value: r, count: o }),
|
|
2477
|
+
reason: i
|
|
2478
|
+
});
|
|
2479
|
+
}
|
|
2480
|
+
function xr(e) {
|
|
2481
|
+
const { smallestPositive: t } = e;
|
|
2482
|
+
if (e.measured === 0 || !(e.max > 0) || t === null)
|
|
2483
|
+
return !1;
|
|
2484
|
+
const n = e.min > 0 ? e.min : t;
|
|
2485
|
+
return Math.log10(e.max) > Math.log10(n);
|
|
2486
|
+
}
|
|
2487
|
+
function zr(e) {
|
|
2488
|
+
return e.measured === 0 || !(e.median > 0) || e.max / e.median <= $r ? "linear" : xr(e) ? "log" : "linear";
|
|
2489
|
+
}
|
|
2490
|
+
function Lr(e, t, n, r) {
|
|
2491
|
+
if (!(t > e))
|
|
2492
|
+
return { binCount: 1, indexOf: () => 0, rangeOf: () => [e, t] };
|
|
2493
|
+
if (r) {
|
|
2494
|
+
const o = t - e + 1, i = Math.ceil(o / Math.min(o, n)), a = Math.ceil(o / i);
|
|
2495
|
+
return {
|
|
2496
|
+
binCount: a,
|
|
2497
|
+
indexOf: (c) => Math.min(Math.floor((c - e) / i), a - 1),
|
|
2498
|
+
rangeOf: (c) => {
|
|
2499
|
+
const u = e + c * i;
|
|
2500
|
+
return [u, Math.min(u + i - 1, t)];
|
|
2501
|
+
}
|
|
2502
|
+
};
|
|
2503
|
+
}
|
|
2504
|
+
const s = (t - e) / n;
|
|
2505
|
+
return {
|
|
2506
|
+
binCount: n,
|
|
2507
|
+
indexOf: (o) => Math.min(Math.floor((o - e) / s), n - 1),
|
|
2508
|
+
rangeOf: (o) => [
|
|
2509
|
+
e + o * s,
|
|
2510
|
+
o === n - 1 ? t : e + (o + 1) * s
|
|
2511
|
+
]
|
|
2512
|
+
};
|
|
2513
|
+
}
|
|
2514
|
+
function jr(e, t, n, r, s) {
|
|
2515
|
+
const o = e > 0 ? 0 : 1, i = o === 0 ? e : n;
|
|
2516
|
+
if (!(t > 0) || i === null || !(i > 0))
|
|
2517
|
+
return null;
|
|
2518
|
+
const a = Math.log10(i), c = Math.log10(t);
|
|
2519
|
+
if (!(c > a))
|
|
2520
|
+
return null;
|
|
2521
|
+
const u = r - o;
|
|
2522
|
+
if (u < 1)
|
|
2523
|
+
return null;
|
|
2524
|
+
const f = (c - a) / u;
|
|
2525
|
+
return {
|
|
2526
|
+
binCount: r,
|
|
2527
|
+
indexOf: (l) => {
|
|
2528
|
+
if (!(l > 0))
|
|
2529
|
+
return 0;
|
|
2530
|
+
const d = Math.floor((Math.log10(l) - a) / f);
|
|
2531
|
+
return o + Math.min(Math.max(d, 0), u - 1);
|
|
2532
|
+
},
|
|
2533
|
+
rangeOf: (l) => {
|
|
2534
|
+
if (l < o)
|
|
2535
|
+
return [e, 0];
|
|
2536
|
+
const d = l - o, p = d === 0 ? i : 10 ** (a + d * f), w = d === u - 1 ? t : 10 ** (a + (d + 1) * f);
|
|
2537
|
+
if (!s)
|
|
2538
|
+
return [p, w];
|
|
2539
|
+
const h = d === 0 ? i : Math.ceil(p);
|
|
2540
|
+
return [h, d === u - 1 ? t : Math.max(h, Math.ceil(w) - 1)];
|
|
2541
|
+
}
|
|
2542
|
+
};
|
|
2543
|
+
}
|
|
2544
|
+
function Dr(e) {
|
|
2545
|
+
if (e === void 0)
|
|
2546
|
+
return Mr;
|
|
2547
|
+
if (!Number.isInteger(e) || e < 1 || e > le)
|
|
2548
|
+
throw new g({
|
|
2549
|
+
code: "E_OPTION_RANGE",
|
|
2550
|
+
source: "run",
|
|
2551
|
+
message: `A histogram takes between 1 and ${le} bins; ${String(e)} was asked for.`,
|
|
2552
|
+
details: { option: "bins", value: e, min: 1, max: le }
|
|
2553
|
+
});
|
|
2554
|
+
return e;
|
|
2555
|
+
}
|
|
2556
|
+
function Pr(e, t) {
|
|
2557
|
+
const n = /* @__PURE__ */ new Map();
|
|
2558
|
+
for (let r = 0; r < e.length; r++) {
|
|
2559
|
+
const s = e.get(r);
|
|
2560
|
+
if (!Number.isFinite(s))
|
|
2561
|
+
continue;
|
|
2562
|
+
const o = n.get(s);
|
|
2563
|
+
if (o === void 0) {
|
|
2564
|
+
if (n.size >= t)
|
|
2565
|
+
return null;
|
|
2566
|
+
n.set(s, 1);
|
|
2567
|
+
continue;
|
|
2568
|
+
}
|
|
2569
|
+
n.set(s, o + 1);
|
|
2570
|
+
}
|
|
2571
|
+
return n;
|
|
2572
|
+
}
|
|
2573
|
+
function Hr(e, t) {
|
|
2574
|
+
const n = Dr(t?.bins), r = t?.integerValued ?? !1, s = Ht(e), o = zr(s), i = Pr(e, n);
|
|
2575
|
+
if (i !== null) {
|
|
2576
|
+
if (i.size === 0)
|
|
2577
|
+
return Object.freeze({
|
|
2578
|
+
bins: Cr,
|
|
2579
|
+
// Nothing was measured, so nothing is on any axis. Reported as linear rather
|
|
2580
|
+
// than as the request, because "log scale" over an empty chart is the same false
|
|
2581
|
+
// caption this whole return type exists to prevent.
|
|
2582
|
+
scale: "linear",
|
|
2583
|
+
suggestedScale: "linear",
|
|
2584
|
+
binning: "empty"
|
|
2585
|
+
});
|
|
2586
|
+
const l = [...i.entries()].sort((d, p) => d[0] - p[0]).map(([d, p]) => Object.freeze({ from: d, to: d, count: p }));
|
|
2587
|
+
return Object.freeze({
|
|
2588
|
+
bins: Object.freeze(l),
|
|
2589
|
+
// One bar per distinct value has no bands to space, so neither axis was applied to
|
|
2590
|
+
// it. Saying "linear" here is what stops a caption claiming a logarithmic layout of
|
|
2591
|
+
// a chart that has none.
|
|
2592
|
+
scale: "linear",
|
|
2593
|
+
suggestedScale: o,
|
|
2594
|
+
binning: "per-value"
|
|
2595
|
+
});
|
|
2596
|
+
}
|
|
2597
|
+
const c = t?.scale === "log" || t?.scale === "auto" && o === "log" ? jr(s.min, s.max, s.smallestPositive, n, r) : null, u = c ?? Lr(s.min, s.max, n, r), f = new Array(u.binCount).fill(0);
|
|
2598
|
+
for (let l = 0; l < e.length; l++) {
|
|
2599
|
+
const d = e.get(l);
|
|
2600
|
+
Number.isFinite(d) && (f[u.indexOf(d)] += 1);
|
|
2601
|
+
}
|
|
2602
|
+
return Object.freeze({
|
|
2603
|
+
bins: Object.freeze(
|
|
2604
|
+
f.map((l, d) => {
|
|
2605
|
+
const [p, w] = u.rangeOf(d);
|
|
2606
|
+
return Object.freeze({ from: p, to: w, count: l });
|
|
2607
|
+
})
|
|
2608
|
+
),
|
|
2609
|
+
// `plan` is null exactly when a logarithmic layout was asked for and could not be built,
|
|
2610
|
+
// which is the case a caption must not get wrong.
|
|
2611
|
+
scale: c === null ? "linear" : "log",
|
|
2612
|
+
suggestedScale: o,
|
|
2613
|
+
binning: "banded"
|
|
2614
|
+
});
|
|
2615
|
+
}
|
|
2616
|
+
const Ur = 10, Gr = 10;
|
|
2617
|
+
function dt(e) {
|
|
2618
|
+
const t = { ids: [], records: [], index: /* @__PURE__ */ new Map() };
|
|
2619
|
+
if (e === void 0)
|
|
2620
|
+
return t;
|
|
2621
|
+
for (const n of e) {
|
|
2622
|
+
const r = t.index.get(n.id);
|
|
2623
|
+
if (r === void 0) {
|
|
2624
|
+
t.index.set(n.id, t.ids.length), t.ids.push(n.id), t.records.push({ ...n.values });
|
|
2625
|
+
continue;
|
|
2626
|
+
}
|
|
2627
|
+
Object.assign(t.records[r], n.values);
|
|
2628
|
+
}
|
|
2629
|
+
return t;
|
|
2630
|
+
}
|
|
2631
|
+
function $e(e, t) {
|
|
2632
|
+
const { records: n } = e;
|
|
2633
|
+
return {
|
|
2634
|
+
length: n.length,
|
|
2635
|
+
get: (r) => Gt(n[r][t])
|
|
2636
|
+
};
|
|
2637
|
+
}
|
|
2638
|
+
function Pe(e, t) {
|
|
2639
|
+
return e.ids.map((n, r) => ({ id: n, value: Gt(e.records[r][t]) }));
|
|
2640
|
+
}
|
|
2641
|
+
function Gt(e) {
|
|
2642
|
+
return typeof e == "number" ? e : Number.NaN;
|
|
2643
|
+
}
|
|
2644
|
+
function He(e) {
|
|
2645
|
+
return typeof e == "string" || typeof e == "number";
|
|
2646
|
+
}
|
|
2647
|
+
function fe(e) {
|
|
2648
|
+
return e.type === "number" || e.type === "integer";
|
|
2649
|
+
}
|
|
2650
|
+
function v(e, t, n) {
|
|
2651
|
+
e[t] === void 0 && (e[t] = n);
|
|
2652
|
+
}
|
|
2653
|
+
function se(e, t, n) {
|
|
2654
|
+
e[t] === void 0 && (e[t] = n);
|
|
2655
|
+
}
|
|
2656
|
+
function Bt(e, t) {
|
|
2657
|
+
const n = /* @__PURE__ */ new Map();
|
|
2658
|
+
for (const r of e.records) {
|
|
2659
|
+
const s = r[t];
|
|
2660
|
+
He(s) && n.set(s, (n.get(s) ?? 0) + 1);
|
|
2661
|
+
}
|
|
2662
|
+
return n;
|
|
2663
|
+
}
|
|
2664
|
+
function Br(e) {
|
|
2665
|
+
const t = [...e.entries()].map(([n, r]) => ({ group: n, size: r }));
|
|
2666
|
+
return t.sort((n, r) => r.size - n.size || Lt(n.group, r.group)), Object.freeze(t.map((n) => Object.freeze(n)));
|
|
2667
|
+
}
|
|
2668
|
+
function Vt(e, t) {
|
|
2669
|
+
const n = e.find((r) => r.name === t)?.normalization;
|
|
2670
|
+
return Pt(n) ? n : "none";
|
|
2671
|
+
}
|
|
2672
|
+
function lt(e, t, n) {
|
|
2673
|
+
const { statistics: r } = Ut($e(e, "value"));
|
|
2674
|
+
for (const s of De(Pe(e, "value"))) {
|
|
2675
|
+
const o = e.index.get(s.id);
|
|
2676
|
+
o !== void 0 && (se(e.records[o], "rank", s.rank), se(e.records[o], "percentile", s.percentile));
|
|
2677
|
+
}
|
|
2678
|
+
r.measured > 0 && (v(t, "min", r.min), v(t, "max", r.max), v(t, "median", r.median), v(t, "mean", r.mean)), v(t, "measured", r.measured), v(t, "tiedAtMin", r.tiedAtMin), v(t, "normalization", Vt(n, "value"));
|
|
2679
|
+
}
|
|
2680
|
+
function ft(e, t, n, r, s) {
|
|
2681
|
+
const o = Bt(e, n);
|
|
2682
|
+
for (const i of e.records) {
|
|
2683
|
+
const a = i[n];
|
|
2684
|
+
He(a) && se(i, r, o.get(a));
|
|
2685
|
+
}
|
|
2686
|
+
v(t, s, o.size), v(t, "sizes", Br(o));
|
|
2687
|
+
}
|
|
2688
|
+
function Vr(e, t) {
|
|
2689
|
+
for (const r of De(Pe(e, "score"))) {
|
|
2690
|
+
const s = e.index.get(r.id);
|
|
2691
|
+
s !== void 0 && se(e.records[s], "rank", r.rank);
|
|
2692
|
+
}
|
|
2693
|
+
const n = [...Bt(e, "category").entries()].map(([r, s]) => ({
|
|
2694
|
+
category: String(r),
|
|
2695
|
+
count: s
|
|
2696
|
+
}));
|
|
2697
|
+
n.sort((r, s) => s.count - r.count || Lt(r.category, s.category)), v(t, "categories", Object.freeze(n.map((r) => Object.freeze(r))));
|
|
2698
|
+
}
|
|
2699
|
+
function J(e, t) {
|
|
2700
|
+
let n = 0;
|
|
2701
|
+
for (const r of e.records)
|
|
2702
|
+
r[t] === !0 && n++;
|
|
2703
|
+
return n;
|
|
2704
|
+
}
|
|
2705
|
+
function pt(e, t) {
|
|
2706
|
+
let n = 0;
|
|
2707
|
+
for (const r of e.records)
|
|
2708
|
+
r[t] !== void 0 && n++;
|
|
2709
|
+
return n;
|
|
2710
|
+
}
|
|
2711
|
+
function Jr(e, t, n, r, s) {
|
|
2712
|
+
switch (e) {
|
|
2713
|
+
case "node-metric":
|
|
2714
|
+
lt(t, r, s);
|
|
2715
|
+
break;
|
|
2716
|
+
case "edge-metric":
|
|
2717
|
+
lt(n, r, s);
|
|
2718
|
+
break;
|
|
2719
|
+
case "community":
|
|
2720
|
+
ft(t, r, "group", "groupSize", "groupCount");
|
|
2721
|
+
break;
|
|
2722
|
+
case "layered-grouping":
|
|
2723
|
+
ft(t, r, "level", "levelSize", "levelCount");
|
|
2724
|
+
break;
|
|
2725
|
+
case "category-table":
|
|
2726
|
+
Vr(t, r);
|
|
2727
|
+
break;
|
|
2728
|
+
case "path":
|
|
2729
|
+
v(r, "length", J(t, "onPath")), v(r, "hops", J(n, "onPath"));
|
|
2730
|
+
break;
|
|
2731
|
+
case "node-set":
|
|
2732
|
+
v(r, "count", J(t, "in"));
|
|
2733
|
+
break;
|
|
2734
|
+
case "edge-set":
|
|
2735
|
+
v(r, "count", J(n, "in"));
|
|
2736
|
+
break;
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
function Wr(e) {
|
|
2740
|
+
switch (e) {
|
|
2741
|
+
case "node-metric":
|
|
2742
|
+
case "edge-metric":
|
|
2743
|
+
return "value";
|
|
2744
|
+
case "category-table":
|
|
2745
|
+
return "score";
|
|
2746
|
+
case "layered-grouping":
|
|
2747
|
+
return "level";
|
|
2748
|
+
default:
|
|
2749
|
+
return null;
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
function Yr(e, t, n) {
|
|
2753
|
+
if (!Array.isArray(e))
|
|
2754
|
+
return;
|
|
2755
|
+
const r = [];
|
|
2756
|
+
for (const s of e) {
|
|
2757
|
+
if (typeof s != "object" || s === null)
|
|
2758
|
+
continue;
|
|
2759
|
+
const o = s, i = o.group ?? o.category, a = o.size ?? o.count;
|
|
2760
|
+
if (He(i) && typeof a == "number" && r.push(Object.freeze(n ? { group: i, size: a, name: Or(r.length + 1) } : { group: i, size: a })), r.length === t)
|
|
2761
|
+
break;
|
|
2762
|
+
}
|
|
2763
|
+
return Object.freeze(r);
|
|
2764
|
+
}
|
|
2765
|
+
class qr {
|
|
2766
|
+
#e;
|
|
2767
|
+
#t;
|
|
2768
|
+
#n;
|
|
2769
|
+
#r;
|
|
2770
|
+
#s;
|
|
2771
|
+
#o;
|
|
2772
|
+
#i = /* @__PURE__ */ new Map();
|
|
2773
|
+
#a = /* @__PURE__ */ new Map();
|
|
2774
|
+
#c = /* @__PURE__ */ new Map();
|
|
2775
|
+
#u;
|
|
2776
|
+
/**
|
|
2777
|
+
* Build a result around storage that has already been filled and frozen.
|
|
2778
|
+
* @param init - What the run published.
|
|
2779
|
+
* @param nodes - The published nodes.
|
|
2780
|
+
* @param edges - The published edges.
|
|
2781
|
+
* @param graph - The graph half, frozen.
|
|
2782
|
+
*/
|
|
2783
|
+
constructor(t, n, r, s) {
|
|
2784
|
+
this.runId = t.runId, this.shape = t.shape, this.fields = Object.freeze([...t.fields]), this.measured = Object.freeze({ nodes: t.measured.nodes, edges: t.measured.edges }), this.graph = s, this.#e = n, this.#t = r, this.#n = t.caveats, this.#r = t.durationMs, this.#s = t.labelOf ?? (() => {
|
|
2785
|
+
}), this.#o = t.reading ?? rr;
|
|
2786
|
+
}
|
|
2787
|
+
/**
|
|
2788
|
+
* One node's fields.
|
|
2789
|
+
* @param id - The node id.
|
|
2790
|
+
* @returns The fields, or undefined when the run produced nothing for that node.
|
|
2791
|
+
*/
|
|
2792
|
+
node(t) {
|
|
2793
|
+
const n = this.#e.index.get(t);
|
|
2794
|
+
return n === void 0 ? void 0 : this.#e.records[n];
|
|
2795
|
+
}
|
|
2796
|
+
/**
|
|
2797
|
+
* One edge's fields.
|
|
2798
|
+
* @param id - The edge id.
|
|
2799
|
+
* @returns The fields, or undefined when the run produced nothing for that edge.
|
|
2800
|
+
*/
|
|
2801
|
+
edge(t) {
|
|
2802
|
+
const n = this.#t.index.get(t);
|
|
2803
|
+
return n === void 0 ? void 0 : this.#t.records[n];
|
|
2804
|
+
}
|
|
2805
|
+
/**
|
|
2806
|
+
* One numeric field as a column.
|
|
2807
|
+
*
|
|
2808
|
+
* The view reads straight through to the result's own storage and its four figures were
|
|
2809
|
+
* computed on the first call, so a histogram, a colour ramp's domain and a summary all walk
|
|
2810
|
+
* one column rather than three copies of it.
|
|
2811
|
+
* @param field - The field name.
|
|
2812
|
+
* @returns A view over the values, without an object per element.
|
|
2813
|
+
* @throws A GraphtyError coded E_UNKNOWN_ATTRIBUTE when the run published no such field, or
|
|
2814
|
+
* E_BAD_COMMAND when the field is not a number published per element.
|
|
2815
|
+
*/
|
|
2816
|
+
column(t) {
|
|
2817
|
+
return this.#p(t).view;
|
|
2818
|
+
}
|
|
2819
|
+
/**
|
|
2820
|
+
* The highest-ranked elements on one field.
|
|
2821
|
+
*
|
|
2822
|
+
* Elements with equal values share a rank and come back in printed-id order, so the top of a
|
|
2823
|
+
* ranking does not reshuffle between two runs that measured the same thing.
|
|
2824
|
+
* @param field - The field to rank on.
|
|
2825
|
+
* @param limit - How many entries to return; the whole ranking when absent.
|
|
2826
|
+
* @returns The entries, best first.
|
|
2827
|
+
* @throws A GraphtyError coded E_OPTION_RANGE when the limit is not a whole number of
|
|
2828
|
+
* entries, E_UNKNOWN_ATTRIBUTE when the run published no such field, or E_BAD_COMMAND when
|
|
2829
|
+
* the field is not a number published per element.
|
|
2830
|
+
*/
|
|
2831
|
+
ranking(t, n) {
|
|
2832
|
+
n !== void 0 && this.#d(n, "limit");
|
|
2833
|
+
const r = this.#a.get(t) ?? this.#g(t);
|
|
2834
|
+
return n === void 0 ? r : Object.freeze(r.slice(0, n));
|
|
2835
|
+
}
|
|
2836
|
+
/**
|
|
2837
|
+
* The top `n` elements on one field, cut only between tie groups: a group of equal values is
|
|
2838
|
+
* taken whole, and only when all of it fits inside `n`. Kept per field and `n`, because a
|
|
2839
|
+
* top selector asks once per element it paints.
|
|
2840
|
+
* @param field - The field to rank on.
|
|
2841
|
+
* @param n - The most elements the top may hold.
|
|
2842
|
+
* @returns The elements taken, and the tie group left out when there was one.
|
|
2843
|
+
* @throws A GraphtyError coded E_OPTION_RANGE when n is not a whole number of entries,
|
|
2844
|
+
* E_UNKNOWN_ATTRIBUTE when the run published no such field, or E_BAD_COMMAND when the
|
|
2845
|
+
* field is not a number published per element.
|
|
2846
|
+
*/
|
|
2847
|
+
top(t, n) {
|
|
2848
|
+
const r = `${String(n)}:${t}`, s = this.#c.get(r);
|
|
2849
|
+
if (s !== void 0)
|
|
2850
|
+
return s;
|
|
2851
|
+
const o = Fr(this.ranking(t), this.#d(n, "n"));
|
|
2852
|
+
return this.#c.set(r, o), o;
|
|
2853
|
+
}
|
|
2854
|
+
/**
|
|
2855
|
+
* Refuse a count of entries that is not a whole number.
|
|
2856
|
+
* @param limit - The count.
|
|
2857
|
+
* @param option - What the caller called it, for the refusal.
|
|
2858
|
+
* @returns The count.
|
|
2859
|
+
* @throws A GraphtyError coded E_OPTION_RANGE when it is not a whole number of entries.
|
|
2860
|
+
*/
|
|
2861
|
+
#d(t, n) {
|
|
2862
|
+
if (!Number.isInteger(t) || t < 0)
|
|
2863
|
+
throw new g({
|
|
2864
|
+
code: "E_OPTION_RANGE",
|
|
2865
|
+
source: "run",
|
|
2866
|
+
message: `A ranking limit is a whole number of entries, not ${String(t)}.`,
|
|
2867
|
+
details: { option: n, value: t, min: 0 },
|
|
2868
|
+
target: { kind: "run", id: this.runId }
|
|
2869
|
+
});
|
|
2870
|
+
return t;
|
|
2871
|
+
}
|
|
2872
|
+
/**
|
|
2873
|
+
* The distribution of one numeric field.
|
|
2874
|
+
*
|
|
2875
|
+
* Whether the field counts things is read off its own descriptor rather than passed in, so a
|
|
2876
|
+
* count metric gets whole-number band edges without the caller knowing that it should.
|
|
2877
|
+
* @param field - The field to bin.
|
|
2878
|
+
* @param options - How to cut the bins.
|
|
2879
|
+
* @returns The distribution, carrying the scale that was applied as well as the bars.
|
|
2880
|
+
* @throws A GraphtyError coded E_OPTION_RANGE when the bin count is outside the permitted
|
|
2881
|
+
* range, E_UNKNOWN_ATTRIBUTE when the run published no such field, or E_BAD_COMMAND when
|
|
2882
|
+
* the field is not a number published per element.
|
|
2883
|
+
*/
|
|
2884
|
+
histogram(t, n) {
|
|
2885
|
+
const r = this.#l(t), s = r.kind === "edge" ? this.#t : this.#e;
|
|
2886
|
+
return Hr($e(s, t), {
|
|
2887
|
+
...n,
|
|
2888
|
+
integerValued: r.type === "integer"
|
|
2889
|
+
});
|
|
2890
|
+
}
|
|
2891
|
+
/**
|
|
2892
|
+
* The bounded form of this result.
|
|
2893
|
+
*
|
|
2894
|
+
* Everything on it is either a single figure or a list the element cut to a fixed length, so
|
|
2895
|
+
* the object is the same size for a graph of a hundred nodes and a graph of a million.
|
|
2896
|
+
* @returns The summary.
|
|
2897
|
+
*/
|
|
2898
|
+
summary() {
|
|
2899
|
+
return this.#u ??= this.#m(), this.#u;
|
|
2900
|
+
}
|
|
2901
|
+
/**
|
|
2902
|
+
* What this result means, in one sentence of plain language.
|
|
2903
|
+
* @param options - The locale and how technical to be.
|
|
2904
|
+
* @returns The sentence.
|
|
2905
|
+
*/
|
|
2906
|
+
reading(t) {
|
|
2907
|
+
return this.#o(this, t ?? {});
|
|
2908
|
+
}
|
|
2909
|
+
/**
|
|
2910
|
+
* The descriptor of one numeric per-element field, without complaining when there is none.
|
|
2911
|
+
*
|
|
2912
|
+
* A summary asks this rather than {@link Result.#descriptorFor} because a summary must not
|
|
2913
|
+
* throw: a run whose field list does not declare the field its shape calls primary is a
|
|
2914
|
+
* defect in that run, and the summary's job is to say what it can about the result rather
|
|
2915
|
+
* than to refuse to describe it at all.
|
|
2916
|
+
* @param field - The field name.
|
|
2917
|
+
* @returns Its descriptor, or null when the run published no numeric field under that name.
|
|
2918
|
+
*/
|
|
2919
|
+
#h(t) {
|
|
2920
|
+
const n = this.fields.find((r) => r.name === t && r.kind !== "graph");
|
|
2921
|
+
return n !== void 0 && fe(n) ? n : null;
|
|
2922
|
+
}
|
|
2923
|
+
/**
|
|
2924
|
+
* The descriptor of one numeric field the run published per element.
|
|
2925
|
+
* @param field - The field name.
|
|
2926
|
+
* @returns Its descriptor.
|
|
2927
|
+
* @throws A GraphtyError naming what went wrong, with the readable fields in its details.
|
|
2928
|
+
*/
|
|
2929
|
+
#l(t) {
|
|
2930
|
+
const n = this.fields.filter((o) => o.name === t), r = n.find((o) => o.kind !== "graph"), s = this.fields.filter((o) => o.kind !== "graph" && fe(o)).map((o) => o.name);
|
|
2931
|
+
if (r === void 0)
|
|
2932
|
+
throw n.length > 0 ? new g({
|
|
2933
|
+
code: "E_BAD_COMMAND",
|
|
2934
|
+
source: "run",
|
|
2935
|
+
message: `"${t}" is a graph-level field of run "${this.runId}"; read it from result.graph.`,
|
|
2936
|
+
details: { field: t, kind: "graph", available: s },
|
|
2937
|
+
target: { kind: "run", id: this.runId }
|
|
2938
|
+
}) : new g({
|
|
2939
|
+
code: "E_UNKNOWN_ATTRIBUTE",
|
|
2940
|
+
source: "run",
|
|
2941
|
+
message: `Run "${this.runId}" published no field named "${t}".`,
|
|
2942
|
+
details: { field: t, available: s, candidates: Nr(t, s) },
|
|
2943
|
+
target: { kind: "run", id: this.runId }
|
|
2944
|
+
});
|
|
2945
|
+
if (!fe(r))
|
|
2946
|
+
throw new g({
|
|
2947
|
+
code: "E_BAD_COMMAND",
|
|
2948
|
+
source: "run",
|
|
2949
|
+
message: `"${t}" is typed "${r.type}", which is not a column of numbers.`,
|
|
2950
|
+
details: { field: t, type: r.type, available: s },
|
|
2951
|
+
target: { kind: "run", id: this.runId }
|
|
2952
|
+
});
|
|
2953
|
+
return r;
|
|
2954
|
+
}
|
|
2955
|
+
/**
|
|
2956
|
+
* The half of the result a per-element field belongs to.
|
|
2957
|
+
* @param field - The field name.
|
|
2958
|
+
* @returns The nodes or the edges.
|
|
2959
|
+
* @throws A GraphtyError naming what went wrong.
|
|
2960
|
+
*/
|
|
2961
|
+
#f(t) {
|
|
2962
|
+
return this.#l(t).kind === "edge" ? this.#t : this.#e;
|
|
2963
|
+
}
|
|
2964
|
+
/**
|
|
2965
|
+
* One field's column and statistics, computed on the first ask and kept.
|
|
2966
|
+
* @param field - The field name.
|
|
2967
|
+
* @returns The view and the statistics behind it.
|
|
2968
|
+
* @throws A GraphtyError naming what went wrong.
|
|
2969
|
+
*/
|
|
2970
|
+
#p(t) {
|
|
2971
|
+
const n = this.#i.get(t);
|
|
2972
|
+
if (n !== void 0)
|
|
2973
|
+
return n;
|
|
2974
|
+
const r = Ut($e(this.#f(t), t));
|
|
2975
|
+
return this.#i.set(t, r), r;
|
|
2976
|
+
}
|
|
2977
|
+
/**
|
|
2978
|
+
* Rank one field for the first time and keep the answer.
|
|
2979
|
+
* @param field - The field to rank on.
|
|
2980
|
+
* @returns The whole ranking, best first.
|
|
2981
|
+
* @throws A GraphtyError naming what went wrong.
|
|
2982
|
+
*/
|
|
2983
|
+
#g(t) {
|
|
2984
|
+
const n = De(Pe(this.#f(t), t));
|
|
2985
|
+
return this.#a.set(t, n), n;
|
|
2986
|
+
}
|
|
2987
|
+
/**
|
|
2988
|
+
* Build the bounded form of this result.
|
|
2989
|
+
* @returns The summary.
|
|
2990
|
+
*/
|
|
2991
|
+
#m() {
|
|
2992
|
+
const t = Wr(this.shape), n = t === null || this.#h(t) === null ? null : t, r = n === null ? null : this.#p(n).statistics, s = r !== null && r.measured > 0 ? r : null, o = n === null ? [] : this.ranking(n, Ur).map(
|
|
2993
|
+
(u) => Object.freeze({
|
|
2994
|
+
id: u.id,
|
|
2995
|
+
label: this.#s(u.id) ?? String(u.id),
|
|
2996
|
+
value: u.value,
|
|
2997
|
+
rank: u.rank,
|
|
2998
|
+
percentile: u.percentile
|
|
2999
|
+
})
|
|
3000
|
+
), i = {
|
|
3001
|
+
count: this.#y(),
|
|
3002
|
+
measured: r === null ? this.#b() : r.measured,
|
|
3003
|
+
min: s === null ? null : s.min,
|
|
3004
|
+
max: s === null ? null : s.max,
|
|
3005
|
+
median: s === null ? null : s.median,
|
|
3006
|
+
mean: s === null ? null : s.mean,
|
|
3007
|
+
tiedAtMin: r === null ? 0 : r.tiedAtMin,
|
|
3008
|
+
normalization: this.#w(n),
|
|
3009
|
+
top: Object.freeze(o),
|
|
3010
|
+
caveats: this.#n,
|
|
3011
|
+
durationMs: this.#r
|
|
3012
|
+
}, a = this.graph.sizes ?? this.graph.categories, c = Yr(a, Gr, this.shape === "community");
|
|
3013
|
+
return Object.freeze(c === void 0 ? i : { ...i, groups: c });
|
|
3014
|
+
}
|
|
3015
|
+
/**
|
|
3016
|
+
* How many elements this result was computed over.
|
|
3017
|
+
*
|
|
3018
|
+
* A shape publishes per-element fields for nodes, for edges or for neither, and the scope a
|
|
3019
|
+
* summary reports is the half or halves it actually measures. A shape that publishes nothing
|
|
3020
|
+
* per element reports none, rather than borrowing the graph's size to look busy.
|
|
3021
|
+
* @returns The count.
|
|
3022
|
+
*/
|
|
3023
|
+
#y() {
|
|
3024
|
+
const t = Re(this.shape), n = t.nodeFields.length > 0 ? this.measured.nodes : 0, r = t.edgeFields.length > 0 ? this.measured.edges : 0;
|
|
3025
|
+
return n + r;
|
|
3026
|
+
}
|
|
3027
|
+
/**
|
|
3028
|
+
* How many elements carry the shape's primary field, for a shape that measures no number.
|
|
3029
|
+
* @returns The count.
|
|
3030
|
+
*/
|
|
3031
|
+
#b() {
|
|
3032
|
+
const t = Re(this.shape), { primaryField: n } = t;
|
|
3033
|
+
if (n === null)
|
|
3034
|
+
return 0;
|
|
3035
|
+
const r = t.nodeFields.includes(n) ? pt(this.#e, n) : 0, s = t.edgeFields.includes(n) ? pt(this.#t, n) : 0;
|
|
3036
|
+
return r + s;
|
|
3037
|
+
}
|
|
3038
|
+
/**
|
|
3039
|
+
* How this result's values were scaled.
|
|
3040
|
+
* @param valueField - The field a summary describes, or null when the shape measures no
|
|
3041
|
+
* number.
|
|
3042
|
+
* @returns The normalisation the run published, the one its field declares, or "none".
|
|
3043
|
+
*/
|
|
3044
|
+
#w(t) {
|
|
3045
|
+
const n = this.graph.normalization;
|
|
3046
|
+
return Pt(n) ? n : t === null ? "none" : Vt(this.fields, t);
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
function Kr(e) {
|
|
3050
|
+
const t = dt(e.nodes), n = dt(e.edges), r = { ...e.graph };
|
|
3051
|
+
Jr(e.shape, t, n, r, e.fields);
|
|
3052
|
+
for (const s of t.records)
|
|
3053
|
+
Object.freeze(s);
|
|
3054
|
+
for (const s of n.records)
|
|
3055
|
+
Object.freeze(s);
|
|
3056
|
+
return new qr(e, t, n, Object.freeze(r));
|
|
3057
|
+
}
|
|
3058
|
+
const Zr = "Computed on the whole graph; values kept for the scope only.";
|
|
3059
|
+
function Jt(e) {
|
|
3060
|
+
const { graph: t, resolution: n } = e;
|
|
3061
|
+
return n.nodeCount === t.nodeCount && n.edgeCount === t.edgeCount;
|
|
3062
|
+
}
|
|
3063
|
+
function Ce(e, t, n) {
|
|
3064
|
+
return t !== E && t < n && oe(e, t);
|
|
3065
|
+
}
|
|
3066
|
+
function pe(e, t) {
|
|
3067
|
+
return `${String(e)} ${t}${e === 1 ? "" : "s"}`;
|
|
3068
|
+
}
|
|
3069
|
+
function Xr(e, t) {
|
|
3070
|
+
if (!e)
|
|
3071
|
+
return Zr;
|
|
3072
|
+
const { nodeCount: n, edgeCount: r } = t.resolution;
|
|
3073
|
+
return t.reading === "induced" ? `Computed on the induced subgraph of ${pe(n, "node")}.` : `Computed on the subgraph of ${pe(n, "node")} and the ${pe(r, "edge")} in scope.`;
|
|
3074
|
+
}
|
|
3075
|
+
function Qr(e, t) {
|
|
3076
|
+
const n = zn(e);
|
|
3077
|
+
if (n === null || Jt(n))
|
|
3078
|
+
return t;
|
|
3079
|
+
const { graph: r, resolution: s } = n, o = (a) => Ce(s.nodes, r.ids.indexOf(a.id), r.nodeCount), i = (a) => Ce(s.edges, kn(r, a.id), r.edgeCount);
|
|
3080
|
+
return {
|
|
3081
|
+
...t,
|
|
3082
|
+
...t.nodes === void 0 ? {} : { nodes: t.nodes.filter(o) },
|
|
3083
|
+
...t.edges === void 0 ? {} : { edges: t.edges.filter(i) },
|
|
3084
|
+
caveats: {
|
|
3085
|
+
...t.caveats,
|
|
3086
|
+
notes: [...t.caveats.notes, Xr(Le(e), n)]
|
|
3087
|
+
}
|
|
3088
|
+
};
|
|
3089
|
+
}
|
|
3090
|
+
function po(e, t, n) {
|
|
3091
|
+
if (n === null || Jt(n))
|
|
3092
|
+
return;
|
|
3093
|
+
const { graph: r, resolution: s } = n;
|
|
3094
|
+
for (const o of e) {
|
|
3095
|
+
if (o.type !== "node-id" && o.type !== "node-set")
|
|
3096
|
+
continue;
|
|
3097
|
+
const i = t[o.name], a = Array.isArray(i) ? i : [i];
|
|
3098
|
+
for (const c of a) {
|
|
3099
|
+
if (typeof c != "string" && typeof c != "number")
|
|
3100
|
+
continue;
|
|
3101
|
+
const u = r.ids.indexOf(c);
|
|
3102
|
+
if (u !== E && !Ce(s.nodes, u, r.nodeCount))
|
|
3103
|
+
throw new g({
|
|
3104
|
+
code: "E_OPTION_RANGE",
|
|
3105
|
+
message: `"${o.name}" names node "${String(c)}", which is outside the run's scope`,
|
|
3106
|
+
source: "run",
|
|
3107
|
+
details: { option: o.name, value: c, reason: "outside-scope" }
|
|
3108
|
+
});
|
|
3109
|
+
}
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
3112
|
+
function es(e) {
|
|
3113
|
+
const t = e.styles?.config.data.knownFields.nodeLabelPath ?? null;
|
|
3114
|
+
if (t === null)
|
|
3115
|
+
return;
|
|
3116
|
+
const n = e.getDataManager();
|
|
3117
|
+
return (r) => {
|
|
3118
|
+
const s = n.getNode(r)?.data[t];
|
|
3119
|
+
return typeof s == "string" || typeof s == "number" ? String(s) : void 0;
|
|
3120
|
+
};
|
|
3121
|
+
}
|
|
3122
|
+
function ho(e) {
|
|
3123
|
+
return { exact: !0, precision: "f64", notes: [], ...e };
|
|
3124
|
+
}
|
|
3125
|
+
const ts = 1024, ns = 16;
|
|
3126
|
+
function rs() {
|
|
3127
|
+
return {
|
|
3128
|
+
input: () => {
|
|
3129
|
+
throw new Error("A detached run context reads no graph: call computeRun, which binds the input.");
|
|
3130
|
+
},
|
|
3131
|
+
signal: new AbortController().signal,
|
|
3132
|
+
report: () => {
|
|
3133
|
+
},
|
|
3134
|
+
yieldNow: () => new Promise((e) => {
|
|
3135
|
+
setTimeout(e, 0);
|
|
3136
|
+
})
|
|
3137
|
+
};
|
|
3138
|
+
}
|
|
3139
|
+
async function go(e, t, n, r) {
|
|
3140
|
+
const s = n.length;
|
|
3141
|
+
e.report({ phase: t, completed: 0, total: s });
|
|
3142
|
+
let o = performance.now();
|
|
3143
|
+
for (let i = 0; i < s; i++)
|
|
3144
|
+
i > 0 && i % ts === 0 && (e.signal.throwIfAborted(), e.report({ phase: t, completed: i, total: s }), performance.now() - o >= ns && (await e.yieldNow(), o = performance.now())), r(n[i], i);
|
|
3145
|
+
e.signal.throwIfAborted(), e.report({ phase: t, completed: s, total: s });
|
|
3146
|
+
}
|
|
3147
|
+
function ss(e, t, n) {
|
|
3148
|
+
const r = n?.find((o) => o.name === e.name && o.kind === e.kind), s = {
|
|
3149
|
+
name: e.name,
|
|
3150
|
+
plainName: r?.plainName ?? e.name,
|
|
3151
|
+
technicalName: r?.technicalName ?? e.name,
|
|
3152
|
+
kind: e.kind,
|
|
3153
|
+
type: e.type,
|
|
3154
|
+
path: Y(t, e.name),
|
|
3155
|
+
...r?.unit === void 0 ? {} : { unit: r.unit }
|
|
3156
|
+
};
|
|
3157
|
+
return e.normalization === void 0 ? s : { ...s, normalization: e.normalization };
|
|
3158
|
+
}
|
|
3159
|
+
class mo extends Se {
|
|
3160
|
+
/** What the last run published, kept so a caller holding the algorithm can read the result. */
|
|
3161
|
+
#e;
|
|
3162
|
+
/**
|
|
3163
|
+
* Fill in what the caller did not pass, and refuse what this algorithm does not declare.
|
|
3164
|
+
*
|
|
3165
|
+
* ONE DECLARATION, NOT TWO. `descriptor.options` is the only list a declared algorithm
|
|
3166
|
+
* writes, and this is what makes that true at the point the values reach the running code:
|
|
3167
|
+
* the same descriptors the catalogue hands a picker are what the caller's values are checked
|
|
3168
|
+
* against. The older `static optionsSchema` remains the answer for a class that declares no
|
|
3169
|
+
* descriptor, which is every algorithm the element itself ships.
|
|
3170
|
+
*
|
|
3171
|
+
* It also fixes the failure vocabulary on the way in. The older schema throws an uncoded
|
|
3172
|
+
* `Error` for a bad value and SILENTLY DROPS a name it does not know, where the run path
|
|
3173
|
+
* refuses the same name with `E_UNKNOWN_OPTION` -- so the same mistake produced three
|
|
3174
|
+
* different outcomes depending on which door the caller came through.
|
|
3175
|
+
* @param options - What the caller asked for.
|
|
3176
|
+
* @returns Every declared option, with the caller's values where they were given and the
|
|
3177
|
+
* declared defaults everywhere else.
|
|
3178
|
+
* @throws A `GraphtyError` with `E_UNKNOWN_OPTION` for a name this algorithm does not
|
|
3179
|
+
* declare, or `E_OPTION_RANGE` for a value it would not accept.
|
|
3180
|
+
*/
|
|
3181
|
+
resolveOptions(t) {
|
|
3182
|
+
const { descriptor: n } = this.constructor;
|
|
3183
|
+
return n === void 0 ? super.resolveOptions(t) : en(n.options, t ?? {}, {
|
|
3184
|
+
kind: "algorithm",
|
|
3185
|
+
id: n.key
|
|
3186
|
+
});
|
|
3187
|
+
}
|
|
3188
|
+
/**
|
|
3189
|
+
* What the last run published.
|
|
3190
|
+
*
|
|
3191
|
+
* THE REPLACEMENT FOR `algorithmResults`. The 1.x entry point used to scatter its numbers onto
|
|
3192
|
+
* the render objects under names it chose for itself, and the only way back to them was to
|
|
3193
|
+
* walk the graph. It returns a result object now, and this is where the 1.x `run()` leaves it,
|
|
3194
|
+
* so the old call shape still has somewhere to read from.
|
|
3195
|
+
* @returns The result, or undefined when nothing has run or there was nothing to compute.
|
|
3196
|
+
*/
|
|
3197
|
+
get result() {
|
|
3198
|
+
return this.#e;
|
|
3199
|
+
}
|
|
3200
|
+
/**
|
|
3201
|
+
* Run the algorithm and publish what it produced on the 1.x result paths.
|
|
3202
|
+
*
|
|
3203
|
+
* The 1.x entry point: it returns nothing, and it publishes under the algorithm's own type
|
|
3204
|
+
* rather than under a run id, because there is no run behind it. Whoever wants the result
|
|
3205
|
+
* calls {@link DeclaredAlgorithm.computeRun}, which is the same work with a run in front of
|
|
3206
|
+
* it.
|
|
3207
|
+
* @returns A promise that settles when the result has been published.
|
|
3208
|
+
*/
|
|
3209
|
+
async run() {
|
|
3210
|
+
await this.computeRun(rs(), this.type);
|
|
3211
|
+
}
|
|
3212
|
+
/**
|
|
3213
|
+
* Compute on behalf of a run, and hand the result back.
|
|
3214
|
+
*
|
|
3215
|
+
* The run machinery's entry point, which is {@link DeclaredAlgorithm.computeRun} under the
|
|
3216
|
+
* name every algorithm answers to.
|
|
3217
|
+
* @param context - A signal, a progress channel and a yield.
|
|
3218
|
+
* @param runId - The id the result is published under.
|
|
3219
|
+
* @param fields - The catalogue's descriptors for this algorithm's fields.
|
|
3220
|
+
* @returns The result, or undefined when there was nothing to compute.
|
|
3221
|
+
* @throws Whatever the context's signal throws once the run has been cancelled.
|
|
3222
|
+
*/
|
|
3223
|
+
publishResult(t, n, r) {
|
|
3224
|
+
return this.computeRun(t, n, r);
|
|
3225
|
+
}
|
|
3226
|
+
/**
|
|
3227
|
+
* Compute this algorithm's result, publish it under a run id, and project the 1.x view of it.
|
|
3228
|
+
*
|
|
3229
|
+
* This is what the run executor calls. The catalogue's own field descriptors are passed in
|
|
3230
|
+
* because the catalogue states what a reader sees a field called and cannot be imported here
|
|
3231
|
+
* without a cycle -- it reads these classes to publish their options.
|
|
3232
|
+
* @param context - What the element gave the run: a signal, a progress channel and a yield.
|
|
3233
|
+
* The graph the run computes over is bound here, as the context's `input`.
|
|
3234
|
+
* @param runId - The id the result is published under, which is the `<runId>` in
|
|
3235
|
+
* `results.<runId>`.
|
|
3236
|
+
* @param declared - The catalogue's descriptors for this algorithm's fields, when the caller
|
|
3237
|
+
* holds them.
|
|
3238
|
+
* @returns The result, or undefined when there was nothing to compute.
|
|
3239
|
+
* @throws Whatever the context's signal throws once the run has been cancelled, which is a
|
|
3240
|
+
* `DOMException` named `AbortError`.
|
|
3241
|
+
*/
|
|
3242
|
+
async computeRun(t, n, r) {
|
|
3243
|
+
const s = Date.now(), o = {
|
|
3244
|
+
signal: t.signal,
|
|
3245
|
+
report: (f) => {
|
|
3246
|
+
t.report(f);
|
|
3247
|
+
},
|
|
3248
|
+
yieldNow: () => t.yieldNow(),
|
|
3249
|
+
input: (f, l) => this.input(f, l)
|
|
3250
|
+
}, i = await this.compute(o);
|
|
3251
|
+
if (i === null)
|
|
3252
|
+
return;
|
|
3253
|
+
const a = this.input("declared"), c = es(this.graph), u = Kr(
|
|
3254
|
+
Qr(this, {
|
|
3255
|
+
...c === void 0 ? {} : { labelOf: c },
|
|
3256
|
+
runId: n,
|
|
3257
|
+
shape: i.shape,
|
|
3258
|
+
fields: i.fields.map((f) => ss(f, n, r)),
|
|
3259
|
+
measured: { nodes: a.nodeCount, edges: a.edgeCount },
|
|
3260
|
+
graph: i.graph,
|
|
3261
|
+
nodes: i.nodes,
|
|
3262
|
+
edges: i.edges,
|
|
3263
|
+
caveats: i.caveats,
|
|
3264
|
+
durationMs: Date.now() - s
|
|
3265
|
+
})
|
|
3266
|
+
);
|
|
3267
|
+
return this.#e = u, u;
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
function yo(e, t = "number") {
|
|
3271
|
+
return [
|
|
3272
|
+
{ name: "value", kind: e, type: t },
|
|
3273
|
+
{ name: "rank", kind: e, type: "integer" },
|
|
3274
|
+
{ name: "percentile", kind: e, type: "number" },
|
|
3275
|
+
{ name: "min", kind: "graph", type: "number" },
|
|
3276
|
+
{ name: "max", kind: "graph", type: "number" },
|
|
3277
|
+
{ name: "median", kind: "graph", type: "number" },
|
|
3278
|
+
{ name: "mean", kind: "graph", type: "number" },
|
|
3279
|
+
{ name: "measured", kind: "graph", type: "integer" },
|
|
3280
|
+
{ name: "normalization", kind: "graph", type: "string" },
|
|
3281
|
+
{ name: "tiedAtMin", kind: "graph", type: "integer" }
|
|
3282
|
+
];
|
|
3283
|
+
}
|
|
3284
|
+
const ht = [
|
|
3285
|
+
{ name: "group", kind: "node", type: "integer" },
|
|
3286
|
+
{ name: "groupSize", kind: "node", type: "integer" },
|
|
3287
|
+
{ name: "groupCount", kind: "graph", type: "integer" },
|
|
3288
|
+
{ name: "sizes", kind: "graph", type: "table" }
|
|
3289
|
+
];
|
|
3290
|
+
function bo(e) {
|
|
3291
|
+
return e ? [...ht, { name: "modularity", kind: "graph", type: "number" }] : ht;
|
|
3292
|
+
}
|
|
3293
|
+
const wo = [
|
|
3294
|
+
{ name: "level", kind: "node", type: "integer" },
|
|
3295
|
+
{ name: "levelSize", kind: "node", type: "integer" },
|
|
3296
|
+
{ name: "levelCount", kind: "graph", type: "integer" },
|
|
3297
|
+
{ name: "sizes", kind: "graph", type: "table" }
|
|
3298
|
+
], vo = [
|
|
3299
|
+
{ name: "onPath", kind: "node", type: "boolean" },
|
|
3300
|
+
{ name: "order", kind: "node", type: "integer" },
|
|
3301
|
+
{ name: "onPath", kind: "edge", type: "boolean" },
|
|
3302
|
+
{ name: "length", kind: "graph", type: "integer" },
|
|
3303
|
+
{ name: "cost", kind: "graph", type: "number" },
|
|
3304
|
+
{ name: "hops", kind: "graph", type: "integer" }
|
|
3305
|
+
];
|
|
3306
|
+
function Oo(e, t) {
|
|
3307
|
+
return [
|
|
3308
|
+
{ name: "in", kind: e, type: "boolean" },
|
|
3309
|
+
{ name: "count", kind: "graph", type: "integer" },
|
|
3310
|
+
{ ...t, kind: "graph" }
|
|
3311
|
+
];
|
|
3312
|
+
}
|
|
3313
|
+
const os = `${Ie}.${vr}`;
|
|
3314
|
+
function N(e) {
|
|
3315
|
+
return { ...e, path: `${os}.${e.name}` };
|
|
3316
|
+
}
|
|
3317
|
+
function ko(e) {
|
|
3318
|
+
return [
|
|
3319
|
+
N({
|
|
3320
|
+
name: "value",
|
|
3321
|
+
plainName: e.plainName,
|
|
3322
|
+
technicalName: e.technicalName,
|
|
3323
|
+
kind: "node",
|
|
3324
|
+
type: e.type ?? "number",
|
|
3325
|
+
...e.unit === void 0 ? {} : { unit: e.unit }
|
|
3326
|
+
}),
|
|
3327
|
+
N({ name: "rank", plainName: "Rank", technicalName: "rank", kind: "node", type: "integer" }),
|
|
3328
|
+
N({
|
|
3329
|
+
name: "percentile",
|
|
3330
|
+
plainName: "Percentile",
|
|
3331
|
+
technicalName: "percentile",
|
|
3332
|
+
kind: "node",
|
|
3333
|
+
type: "number"
|
|
3334
|
+
}),
|
|
3335
|
+
N({ name: "min", plainName: "Lowest", technicalName: "min", kind: "graph", type: "number" }),
|
|
3336
|
+
N({ name: "max", plainName: "Highest", technicalName: "max", kind: "graph", type: "number" }),
|
|
3337
|
+
N({ name: "median", plainName: "Middle", technicalName: "median", kind: "graph", type: "number" }),
|
|
3338
|
+
N({ name: "mean", plainName: "Average", technicalName: "mean", kind: "graph", type: "number" }),
|
|
3339
|
+
N({
|
|
3340
|
+
name: "measured",
|
|
3341
|
+
plainName: "Measured",
|
|
3342
|
+
technicalName: "measured",
|
|
3343
|
+
kind: "graph",
|
|
3344
|
+
type: "integer"
|
|
3345
|
+
}),
|
|
3346
|
+
N({
|
|
3347
|
+
name: "normalization",
|
|
3348
|
+
plainName: "Normalization",
|
|
3349
|
+
technicalName: "normalization",
|
|
3350
|
+
kind: "graph",
|
|
3351
|
+
type: "string"
|
|
3352
|
+
}),
|
|
3353
|
+
N({
|
|
3354
|
+
name: "tiedAtMin",
|
|
3355
|
+
plainName: "Tied at the lowest value",
|
|
3356
|
+
technicalName: "tiedAtMin",
|
|
3357
|
+
kind: "graph",
|
|
3358
|
+
type: "integer"
|
|
3359
|
+
})
|
|
3360
|
+
];
|
|
3361
|
+
}
|
|
3362
|
+
const is = 12;
|
|
3363
|
+
function Ao(e, t = {}) {
|
|
3364
|
+
return (as(e) ? cs(e) : us(e)).map((r) => {
|
|
3365
|
+
const s = { ...r.meta, ...t.meta?.[r.name] }, o = r.node === null ? fs(r.name, s, r.failure ?? "the schema could not be converted") : ls(r.name, r.node, s), i = t.overrides?.[r.name];
|
|
3366
|
+
return i === void 0 ? o : { ...o, ...i };
|
|
3367
|
+
});
|
|
3368
|
+
}
|
|
3369
|
+
function as(e) {
|
|
3370
|
+
return typeof e != "object" || e === null ? !1 : "_zod" in e || "_def" in e;
|
|
3371
|
+
}
|
|
3372
|
+
function cs(e) {
|
|
3373
|
+
const t = Wt(e);
|
|
3374
|
+
if (t === null)
|
|
3375
|
+
return [];
|
|
3376
|
+
const { properties: n } = t;
|
|
3377
|
+
return n === void 0 ? [] : Object.entries(n).map(([r, s]) => ({ name: r, node: Yt(s, t) }));
|
|
3378
|
+
}
|
|
3379
|
+
function us(e) {
|
|
3380
|
+
const t = Object.entries(e), n = {};
|
|
3381
|
+
for (const [o, i] of t)
|
|
3382
|
+
n[o] = i.schema;
|
|
3383
|
+
const r = ds(n), s = r?.properties;
|
|
3384
|
+
return t.map(([o, i]) => {
|
|
3385
|
+
const a = s?.[o];
|
|
3386
|
+
return r === null || a === void 0 ? {
|
|
3387
|
+
name: o,
|
|
3388
|
+
node: null,
|
|
3389
|
+
failure: "the schema could not be converted to JSON Schema",
|
|
3390
|
+
meta: i.meta
|
|
3391
|
+
} : { name: o, node: Yt(a, r), meta: i.meta };
|
|
3392
|
+
});
|
|
3393
|
+
}
|
|
3394
|
+
function Wt(e) {
|
|
3395
|
+
try {
|
|
3396
|
+
return bt.toJSONSchema(e, { io: "input", unrepresentable: "any" });
|
|
3397
|
+
} catch {
|
|
3398
|
+
return null;
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
function ds(e) {
|
|
3402
|
+
try {
|
|
3403
|
+
return Wt(bt.object(e));
|
|
3404
|
+
} catch {
|
|
3405
|
+
return null;
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
const gt = "#/$defs/";
|
|
3409
|
+
function Yt(e, t) {
|
|
3410
|
+
const n = e.$ref;
|
|
3411
|
+
if (n === void 0 || !n.startsWith(gt))
|
|
3412
|
+
return e;
|
|
3413
|
+
const r = n.slice(gt.length).replaceAll("~1", "/").replaceAll("~0", "~");
|
|
3414
|
+
return t.$defs?.[r] ?? e;
|
|
3415
|
+
}
|
|
3416
|
+
function ls(e, t, n) {
|
|
3417
|
+
const r = qt(t, 0), s = ps(r), o = {
|
|
3418
|
+
name: e,
|
|
3419
|
+
plainName: n.label ?? Ue(e),
|
|
3420
|
+
technicalName: e,
|
|
3421
|
+
type: s.type
|
|
3422
|
+
}, i = n.description ?? t.description ?? s.node?.description;
|
|
3423
|
+
i !== void 0 && (o.description = i), "default" in t && (o.default = t.default);
|
|
3424
|
+
const a = s.node;
|
|
3425
|
+
if (a !== void 0 && (s.type === "number" || s.type === "integer")) {
|
|
3426
|
+
const u = mt(a.minimum ?? a.exclusiveMinimum), f = mt(a.maximum ?? a.exclusiveMaximum);
|
|
3427
|
+
u !== void 0 && (o.min = u), f !== void 0 && (o.max = f);
|
|
3428
|
+
}
|
|
3429
|
+
const c = n.step ?? a?.multipleOf;
|
|
3430
|
+
return c !== void 0 && (o.step = c), s.values !== void 0 && (o.values = s.values), n.group !== void 0 && (o.group = n.group), n.advanced !== void 0 && (o.advanced = n.advanced), s.unsupportedReason !== void 0 && (o.unsupportedReason = s.unsupportedReason), o;
|
|
3431
|
+
}
|
|
3432
|
+
function fs(e, t, n) {
|
|
3433
|
+
const r = {
|
|
3434
|
+
name: e,
|
|
3435
|
+
plainName: t.label ?? Ue(e),
|
|
3436
|
+
technicalName: e,
|
|
3437
|
+
type: "unknown",
|
|
3438
|
+
unsupportedReason: n
|
|
3439
|
+
};
|
|
3440
|
+
return t.description !== void 0 && (r.description = t.description), t.step !== void 0 && (r.step = t.step), t.group !== void 0 && (r.group = t.group), t.advanced !== void 0 && (r.advanced = t.advanced), r;
|
|
3441
|
+
}
|
|
3442
|
+
function qt(e, t) {
|
|
3443
|
+
if (t >= is)
|
|
3444
|
+
return { arms: [], nullable: !1, unresolvedRef: !0 };
|
|
3445
|
+
if (e.$ref !== void 0)
|
|
3446
|
+
return { arms: [], nullable: !1, unresolvedRef: !0 };
|
|
3447
|
+
const n = e.anyOf ?? e.oneOf;
|
|
3448
|
+
if (n === void 0)
|
|
3449
|
+
return e.type === "null" ? { arms: [], nullable: !0, unresolvedRef: !1 } : { arms: [e], nullable: !1, unresolvedRef: !1 };
|
|
3450
|
+
const r = { arms: [], nullable: !1, unresolvedRef: !1 };
|
|
3451
|
+
for (const s of n) {
|
|
3452
|
+
const o = qt(s, t + 1);
|
|
3453
|
+
r.arms.push(...o.arms), r.nullable = r.nullable || o.nullable, r.unresolvedRef = r.unresolvedRef || o.unresolvedRef;
|
|
3454
|
+
}
|
|
3455
|
+
return r;
|
|
3456
|
+
}
|
|
3457
|
+
function ps(e) {
|
|
3458
|
+
if (e.arms.length === 0)
|
|
3459
|
+
return e.unresolvedRef ? {
|
|
3460
|
+
type: "unknown",
|
|
3461
|
+
unsupportedReason: "the schema is recursive, so it has no single value type"
|
|
3462
|
+
} : {
|
|
3463
|
+
type: "unknown",
|
|
3464
|
+
unsupportedReason: e.nullable ? "the only value the schema accepts is null" : "the schema declares no value type"
|
|
3465
|
+
};
|
|
3466
|
+
const t = gs(e.arms);
|
|
3467
|
+
if (t !== void 0)
|
|
3468
|
+
return { type: "enum", node: e.arms[0], values: t };
|
|
3469
|
+
if (e.arms.length === 1)
|
|
3470
|
+
return hs(e.arms[0]);
|
|
3471
|
+
const n = e.arms.map((r) => Kt(r));
|
|
3472
|
+
return n.length === 2 && n.includes("string") && n.includes("number") ? { type: "node-id" } : {
|
|
3473
|
+
type: "unknown",
|
|
3474
|
+
unsupportedReason: `the schema is a union of ${n.join(" and ")}, which has no single control`
|
|
3475
|
+
};
|
|
3476
|
+
}
|
|
3477
|
+
function hs(e) {
|
|
3478
|
+
switch (Kt(e)) {
|
|
3479
|
+
case "integer":
|
|
3480
|
+
return { type: "integer", node: e };
|
|
3481
|
+
case "number":
|
|
3482
|
+
return { type: "number", node: e };
|
|
3483
|
+
case "boolean":
|
|
3484
|
+
return { type: "boolean", node: e };
|
|
3485
|
+
case "string":
|
|
3486
|
+
return { type: "string", node: e };
|
|
3487
|
+
case "array":
|
|
3488
|
+
return {
|
|
3489
|
+
type: "unknown",
|
|
3490
|
+
node: e,
|
|
3491
|
+
unsupportedReason: "an array option has no descriptor type; give it one with an override"
|
|
3492
|
+
};
|
|
3493
|
+
case "object":
|
|
3494
|
+
return {
|
|
3495
|
+
type: "unknown",
|
|
3496
|
+
node: e,
|
|
3497
|
+
unsupportedReason: "an object or record option has no descriptor type; give it one with an override"
|
|
3498
|
+
};
|
|
3499
|
+
default:
|
|
3500
|
+
return {
|
|
3501
|
+
type: "unknown",
|
|
3502
|
+
node: e,
|
|
3503
|
+
unsupportedReason: "the Zod construct has no JSON Schema type, so its values cannot be classified"
|
|
3504
|
+
};
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
function gs(e) {
|
|
3508
|
+
const t = [];
|
|
3509
|
+
for (const r of e)
|
|
3510
|
+
if (r.enum !== void 0)
|
|
3511
|
+
t.push(...r.enum);
|
|
3512
|
+
else if ("const" in r)
|
|
3513
|
+
t.push(r.const);
|
|
3514
|
+
else
|
|
3515
|
+
return;
|
|
3516
|
+
if (t.length === 0)
|
|
3517
|
+
return;
|
|
3518
|
+
const n = [];
|
|
3519
|
+
for (const r of t) {
|
|
3520
|
+
if (typeof r != "string" && typeof r != "number" && typeof r != "boolean")
|
|
3521
|
+
return;
|
|
3522
|
+
const s = String(r);
|
|
3523
|
+
n.push({ value: s, label: Ue(s) });
|
|
3524
|
+
}
|
|
3525
|
+
return n;
|
|
3526
|
+
}
|
|
3527
|
+
function Kt(e) {
|
|
3528
|
+
const { type: t } = e;
|
|
3529
|
+
return typeof t == "string" ? t : Array.isArray(t) && t.length > 0 ? t[0] : "none";
|
|
3530
|
+
}
|
|
3531
|
+
function mt(e) {
|
|
3532
|
+
if (!(e === Number.MAX_SAFE_INTEGER || e === -Number.MAX_SAFE_INTEGER))
|
|
3533
|
+
return e;
|
|
3534
|
+
}
|
|
3535
|
+
function Ue(e) {
|
|
3536
|
+
const t = e.replace(/([a-z0-9])([A-Z])/gu, "$1 $2").replace(/[_-]+/gu, " ").trim();
|
|
3537
|
+
return t === "" ? e : t.split(/\s+/u).map((n) => n.charAt(0).toUpperCase() + n.slice(1)).join(" ");
|
|
3538
|
+
}
|
|
3539
|
+
export {
|
|
3540
|
+
me as $,
|
|
3541
|
+
Se as A,
|
|
3542
|
+
xs as B,
|
|
3543
|
+
an as C,
|
|
3544
|
+
Ms as D,
|
|
3545
|
+
Es as E,
|
|
3546
|
+
At as F,
|
|
3547
|
+
pn as G,
|
|
3548
|
+
un as H,
|
|
3549
|
+
wt as I,
|
|
3550
|
+
Ss as J,
|
|
3551
|
+
Ys as K,
|
|
3552
|
+
wo as L,
|
|
3553
|
+
qs as M,
|
|
3554
|
+
es as N,
|
|
3555
|
+
O,
|
|
3556
|
+
vo as P,
|
|
3557
|
+
Kr as Q,
|
|
3558
|
+
io as R,
|
|
3559
|
+
Qr as S,
|
|
3560
|
+
Cs as T,
|
|
3561
|
+
$s as U,
|
|
3562
|
+
Ts as V,
|
|
3563
|
+
_s as W,
|
|
3564
|
+
z as X,
|
|
3565
|
+
ns as Y,
|
|
3566
|
+
Fr as Z,
|
|
3567
|
+
De as _,
|
|
3568
|
+
mo as a,
|
|
3569
|
+
Ds as a0,
|
|
3570
|
+
ze as a1,
|
|
3571
|
+
Mt as a2,
|
|
3572
|
+
we as a3,
|
|
3573
|
+
Ps as a4,
|
|
3574
|
+
Hs as a5,
|
|
3575
|
+
Ls as a6,
|
|
3576
|
+
js as a7,
|
|
3577
|
+
In as a8,
|
|
3578
|
+
Us as a9,
|
|
3579
|
+
uo as aA,
|
|
3580
|
+
Qs as aB,
|
|
3581
|
+
po as aC,
|
|
3582
|
+
Zs as aD,
|
|
3583
|
+
Bs as aE,
|
|
3584
|
+
Ks as aF,
|
|
3585
|
+
ve as aa,
|
|
3586
|
+
Ct as ab,
|
|
3587
|
+
On as ac,
|
|
3588
|
+
vn as ad,
|
|
3589
|
+
Ws as ae,
|
|
3590
|
+
Js as af,
|
|
3591
|
+
B as ag,
|
|
3592
|
+
Gs as ah,
|
|
3593
|
+
Vs as ai,
|
|
3594
|
+
Sn as aj,
|
|
3595
|
+
An as ak,
|
|
3596
|
+
Ht as al,
|
|
3597
|
+
fo as am,
|
|
3598
|
+
oo as an,
|
|
3599
|
+
eo as ao,
|
|
3600
|
+
Re as ap,
|
|
3601
|
+
kn as aq,
|
|
3602
|
+
Lt as ar,
|
|
3603
|
+
Nr as as,
|
|
3604
|
+
so as at,
|
|
3605
|
+
ro as au,
|
|
3606
|
+
no as av,
|
|
3607
|
+
to as aw,
|
|
3608
|
+
Or as ax,
|
|
3609
|
+
ao as ay,
|
|
3610
|
+
lo as az,
|
|
3611
|
+
zs as b,
|
|
3612
|
+
co as c,
|
|
3613
|
+
Ns as d,
|
|
3614
|
+
bo as e,
|
|
3615
|
+
ho as f,
|
|
3616
|
+
Xs as g,
|
|
3617
|
+
go as h,
|
|
3618
|
+
yo as i,
|
|
3619
|
+
Fs as j,
|
|
3620
|
+
As as k,
|
|
3621
|
+
Bn as l,
|
|
3622
|
+
N as m,
|
|
3623
|
+
ko as n,
|
|
3624
|
+
Ao as o,
|
|
3625
|
+
on as p,
|
|
3626
|
+
Is as q,
|
|
3627
|
+
ks as r,
|
|
3628
|
+
Oo as s,
|
|
3629
|
+
Ie as t,
|
|
3630
|
+
je as u,
|
|
3631
|
+
Un as v,
|
|
3632
|
+
rr as w,
|
|
3633
|
+
Rs as x,
|
|
3634
|
+
br as y,
|
|
3635
|
+
Y as z
|
|
3636
|
+
};
|