@qe-libs/rena-wasm 0.1.1 → 0.1.2
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/README.md +8 -6
- package/package.json +1 -1
- package/src/index.js +20 -8
- package/src/pipeline.js +45 -0
package/README.md
CHANGED
|
@@ -32,12 +32,14 @@ const model = ena.fit(rows, {
|
|
|
32
32
|
dims: 2,
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
model.centroids
|
|
36
|
-
model.
|
|
37
|
-
model.
|
|
35
|
+
model.model.centroids // Float64Array nUnits × dims
|
|
36
|
+
model.lineWeights // Float64Array nUnits × nConnections (normed)
|
|
37
|
+
model.connectionCounts // Float64Array nUnits × nConnections (raw unit counts)
|
|
38
|
+
model.rowConnectionCounts // Float64Array nRows × nConnections (raw row counts)
|
|
39
|
+
model.rotation.nodes // Float64Array nCodes × dims
|
|
38
40
|
model.connectionNames // ['Data & Technical.Constraints', ...]
|
|
39
|
-
model.unitLabels
|
|
40
|
-
model.columnNames
|
|
41
|
+
model.model.unitLabels // ['UserName1_ConditionA', ...]
|
|
42
|
+
model.rotation.columnNames // ['SVD1', 'SVD2']
|
|
41
43
|
|
|
42
44
|
// Per-unit helpers
|
|
43
45
|
model.centroid('Alice_A') // number[] length = dims
|
|
@@ -70,7 +72,7 @@ const model = ena.fit(rows, {
|
|
|
70
72
|
Returns raw (un-normalised) network vectors without running the full pipeline.
|
|
71
73
|
|
|
72
74
|
```js
|
|
73
|
-
const {
|
|
75
|
+
const { connectionCounts, rowConnectionCounts, unitLabels, connectionNames, nUnits, nConnections } =
|
|
74
76
|
ena.accumulate(rows, { codes, units, conversations, window: 4 });
|
|
75
77
|
```
|
|
76
78
|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Top-level fields (= R's set$...):
|
|
14
14
|
* connectionCounts Float64Array (nUnits × nConnections) — raw accumulation
|
|
15
|
+
* rowConnectionCounts Float64Array (nRows × nConnections) — per-row raw accumulation
|
|
15
16
|
* lineWeights Float64Array (nUnits × nConnections) — sphere-normed
|
|
16
17
|
* points Float64Array (nUnits × dims) — projected positions
|
|
17
18
|
* rotationMatrix Float64Array (nConnections × dims) — rotation vectors
|
|
@@ -23,6 +24,7 @@
|
|
|
23
24
|
* dims number
|
|
24
25
|
*
|
|
25
26
|
* model sub-object (= R's set$model$...):
|
|
27
|
+
* model.rowConnectionCounts Float64Array (nRows × nConnections) — per-row raw accumulation
|
|
26
28
|
* model.centroids Float64Array (nUnits × dims) — LWS centroids
|
|
27
29
|
* model.variance number[] variance explained per dim
|
|
28
30
|
* model.unitLabels string[]
|
|
@@ -41,7 +43,7 @@
|
|
|
41
43
|
import loadLibQE from '@qe-libs/libqe-wasm';
|
|
42
44
|
import { parseData } from './data.js';
|
|
43
45
|
import {
|
|
44
|
-
accumulate, sphereNorm, center,
|
|
46
|
+
accumulate, accumulateWithRows, sphereNorm, center,
|
|
45
47
|
rotateSVD, rotateMeans, rotateGeneralized,
|
|
46
48
|
project, nodePositions, spaceDistCorr,
|
|
47
49
|
} from './pipeline.js';
|
|
@@ -107,6 +109,7 @@ class ENAModel {
|
|
|
107
109
|
constructor(opts) {
|
|
108
110
|
// ── top-level fields (= R's set$...) ────────────────────────────────
|
|
109
111
|
this.connectionCounts = opts.connectionCounts; // raw networks
|
|
112
|
+
this.rowConnectionCounts = opts.rowConnectionCounts;
|
|
110
113
|
this.lineWeights = opts.lineWeights; // sphere-normed networks
|
|
111
114
|
this.points = opts.points; // projected unit positions
|
|
112
115
|
this.rotationMatrix = opts.rotationMatrix; // n_connections × dims
|
|
@@ -118,6 +121,7 @@ class ENAModel {
|
|
|
118
121
|
|
|
119
122
|
// ── model sub-object (= R's set$model$...) ───────────────────────────
|
|
120
123
|
this.model = {
|
|
124
|
+
rowConnectionCounts: opts.rowConnectionCounts,
|
|
121
125
|
centroids: opts.centroids, // LWS positions
|
|
122
126
|
variance: opts.variance, // variance explained
|
|
123
127
|
unitLabels: opts.unitLabels,
|
|
@@ -186,7 +190,8 @@ class ENAModel {
|
|
|
186
190
|
// ── shared pipeline (post-accumulation) ──────────────────────────────────────
|
|
187
191
|
|
|
188
192
|
function runPipeline(qe, rawNetworks, nUnits, nConnections, codes, unitLabels,
|
|
189
|
-
metaData, rotMethod, groupA, groupB, dims, gParams
|
|
193
|
+
metaData, rotMethod, groupA, groupB, dims, gParams,
|
|
194
|
+
rowConnectionCounts = null) {
|
|
190
195
|
const connectionNames = qe.connection_names(codes);
|
|
191
196
|
|
|
192
197
|
// Sphere norm → lineWeights (= R's set$line.weights)
|
|
@@ -243,6 +248,7 @@ function runPipeline(qe, rawNetworks, nUnits, nConnections, codes, unitLabels,
|
|
|
243
248
|
return new ENAModel({
|
|
244
249
|
// top-level
|
|
245
250
|
connectionCounts: rawNetworks,
|
|
251
|
+
rowConnectionCounts,
|
|
246
252
|
lineWeights,
|
|
247
253
|
points,
|
|
248
254
|
rotationMatrix,
|
|
@@ -322,7 +328,7 @@ export default async function loadENA() {
|
|
|
322
328
|
unitOf, convoGroups, metaData } =
|
|
323
329
|
parseData(rows, codes, units, conversations);
|
|
324
330
|
|
|
325
|
-
let rawNetworks, nConnections;
|
|
331
|
+
let rawNetworks, rowConnectionCounts = null, nConnections;
|
|
326
332
|
|
|
327
333
|
if (tensorDef) {
|
|
328
334
|
rawNetworks = accumulateTensor(
|
|
@@ -331,10 +337,12 @@ export default async function loadENA() {
|
|
|
331
337
|
);
|
|
332
338
|
nConnections = ordered ? nCodes * nCodes : qe.choose_two(nCodes);
|
|
333
339
|
} else {
|
|
334
|
-
|
|
340
|
+
const accumulated = accumulateWithRows(
|
|
335
341
|
qe, codeMatrix, nRows, nCodes, nUnits,
|
|
336
342
|
unitOf, convoGroups, windowSize, binary
|
|
337
343
|
);
|
|
344
|
+
rawNetworks = accumulated.networks;
|
|
345
|
+
rowConnectionCounts = accumulated.rowConnectionCounts;
|
|
338
346
|
nConnections = qe.choose_two(nCodes);
|
|
339
347
|
}
|
|
340
348
|
|
|
@@ -368,7 +376,8 @@ export default async function loadENA() {
|
|
|
368
376
|
}
|
|
369
377
|
|
|
370
378
|
return runPipeline(qe, rawNetworks, nUnits, nConnections, codes,
|
|
371
|
-
unitLabels, metaData, rotMethod, groupA, groupB,
|
|
379
|
+
unitLabels, metaData, rotMethod, groupA, groupB,
|
|
380
|
+
dims, gParams, rowConnectionCounts);
|
|
372
381
|
},
|
|
373
382
|
|
|
374
383
|
/**
|
|
@@ -379,6 +388,7 @@ export default async function loadENA() {
|
|
|
379
388
|
* @param {object} opts - codes, units, conversations, window, binary, ordered, tensor
|
|
380
389
|
* @returns {{
|
|
381
390
|
* connectionCounts: Float64Array,
|
|
391
|
+
* rowConnectionCounts: Float64Array | null,
|
|
382
392
|
* unitLabels: string[],
|
|
383
393
|
* connectionNames: string[],
|
|
384
394
|
* metaData: Object[],
|
|
@@ -401,7 +411,7 @@ export default async function loadENA() {
|
|
|
401
411
|
unitOf, convoGroups, metaData } =
|
|
402
412
|
parseData(rows, codes, units, conversations);
|
|
403
413
|
|
|
404
|
-
let networks, nConnections;
|
|
414
|
+
let networks, rowConnectionCounts = null, nConnections;
|
|
405
415
|
|
|
406
416
|
if (tensorDef) {
|
|
407
417
|
networks = accumulateTensor(
|
|
@@ -410,10 +420,12 @@ export default async function loadENA() {
|
|
|
410
420
|
);
|
|
411
421
|
nConnections = ordered ? nCodes * nCodes : qe.choose_two(nCodes);
|
|
412
422
|
} else {
|
|
413
|
-
|
|
423
|
+
const accumulated = accumulateWithRows(
|
|
414
424
|
qe, codeMatrix, nRows, nCodes, nUnits,
|
|
415
425
|
unitOf, convoGroups, windowSize, binary
|
|
416
426
|
);
|
|
427
|
+
networks = accumulated.networks;
|
|
428
|
+
rowConnectionCounts = accumulated.rowConnectionCounts;
|
|
417
429
|
nConnections = qe.choose_two(nCodes);
|
|
418
430
|
}
|
|
419
431
|
|
|
@@ -448,7 +460,7 @@ export default async function loadENA() {
|
|
|
448
460
|
|
|
449
461
|
const connectionNames = qe.connection_names(codes);
|
|
450
462
|
return {
|
|
451
|
-
connectionCounts: networks, unitLabels, connectionNames,
|
|
463
|
+
connectionCounts: networks, rowConnectionCounts, unitLabels, connectionNames,
|
|
452
464
|
metaData, nUnits, nConnections,
|
|
453
465
|
// Retained so tuneWindowSize() can rebuild at other window sizes
|
|
454
466
|
// (= R's ENAAccumulation$`_function.call`).
|
package/src/pipeline.js
CHANGED
|
@@ -174,6 +174,51 @@ export function accumulate(qe, codeMatrix, nRows, nCodes, nUnits,
|
|
|
174
174
|
return networks;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Accumulate windowed co-occurrences and retain both per-unit and per-row
|
|
179
|
+
* connection vectors.
|
|
180
|
+
*
|
|
181
|
+
* @returns {{ networks: Float64Array, rowConnectionCounts: Float64Array }}
|
|
182
|
+
*/
|
|
183
|
+
export function accumulateWithRows(qe, codeMatrix, nRows, nCodes, nUnits,
|
|
184
|
+
unitOf, convoGroups, windowSize = 4, binary = true) {
|
|
185
|
+
const nConnections = qe.choose_two(nCodes);
|
|
186
|
+
const networks = new Float64Array(nUnits * nConnections);
|
|
187
|
+
const rowConnectionCounts = new Float64Array(nRows * nConnections);
|
|
188
|
+
|
|
189
|
+
for (const [, rowIndices] of convoGroups) {
|
|
190
|
+
const nConvo = rowIndices.length;
|
|
191
|
+
|
|
192
|
+
const convoCodes = new Float64Array(nConvo * nCodes);
|
|
193
|
+
for (let r = 0; r < nConvo; r++) {
|
|
194
|
+
const src = rowIndices[r];
|
|
195
|
+
convoCodes.set(
|
|
196
|
+
codeMatrix.subarray(src * nCodes, src * nCodes + nCodes),
|
|
197
|
+
r * nCodes
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const stanza = qe.accumulate_stanza(
|
|
202
|
+
convoCodes, nConvo, nCodes, windowSize, 0, binary
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
for (let r = 0; r < nConvo; r++) {
|
|
206
|
+
const src = rowIndices[r];
|
|
207
|
+
const unit = unitOf[src];
|
|
208
|
+
const offset = r * nConnections;
|
|
209
|
+
const rowOut = src * nConnections;
|
|
210
|
+
|
|
211
|
+
for (let c = 0; c < nConnections; c++) {
|
|
212
|
+
const value = stanza.data[offset + c];
|
|
213
|
+
rowConnectionCounts[rowOut + c] = value;
|
|
214
|
+
networks[unit * nConnections + c] += value;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return { networks, rowConnectionCounts };
|
|
220
|
+
}
|
|
221
|
+
|
|
177
222
|
// ── normalization (sphere norm) ───────────────────────────────────────────────
|
|
178
223
|
|
|
179
224
|
/**
|