@qe-libs/rena-wasm 0.1.14 → 0.1.16
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 +52 -11
- package/demo/RS.csv +3825 -0
- package/dist/libena.js +1 -1
- package/dist/libena.wasm +0 -0
- package/package.json +4 -3
- package/src/index.js +146 -47
- package/src/pipeline.js +16 -4
- package/src/tensor.js +51 -33
package/src/pipeline.js
CHANGED
|
@@ -319,17 +319,29 @@ export function project(centered, nUnits, nConnections, rotation, rotRows, rotCo
|
|
|
319
319
|
/**
|
|
320
320
|
* Compute code node positions via least-squares (LWS).
|
|
321
321
|
*
|
|
322
|
-
* @param {boolean} [directed=false] Use
|
|
322
|
+
* @param {boolean} [directed=false] Use libena's directed_node_positions (for
|
|
323
323
|
* ordered n² networks), as rENA's optimize() does for ordered sets.
|
|
324
|
+
* @param {number} [selfWeight=2] Weight of a self-connection in its code's
|
|
325
|
+
* node weight (2 = row + column sum, the default; 1 = once).
|
|
326
|
+
* @param {{from, to}|null} [key=null] Unordered: libena's column key
|
|
327
|
+
* (undirected_connection_key); the nodes come from node_positions_by_key --
|
|
328
|
+
* the same as node_positions for choose(n, 2) columns, and it also places
|
|
329
|
+
* self-connection columns. null keeps node_positions.
|
|
330
|
+
* @param {number|null} [nCodes=null] Number of codes (with `key`).
|
|
324
331
|
* @returns {{ nodes: Float64Array, nodeRows: number, nodeCols: number,
|
|
325
332
|
* centroids: Float64Array|null }}
|
|
326
333
|
* nodes — code positions in ENA space (= R's rotation$nodes)
|
|
327
334
|
* centroids — LWS unit centroid positions (= R's model$centroids), or null
|
|
328
335
|
* if libqe does not expose them
|
|
329
336
|
*/
|
|
330
|
-
export function nodePositions(qe, networks, nUnits, nConnections, points, nDims,
|
|
331
|
-
|
|
332
|
-
const r =
|
|
337
|
+
export function nodePositions(qe, networks, nUnits, nConnections, points, nDims,
|
|
338
|
+
directed = false, selfWeight = 2, key = null, nCodes = null) {
|
|
339
|
+
const r = directed
|
|
340
|
+
? qe.directed_node_positions(networks, nUnits, nConnections, points, nUnits, nDims, nDims, selfWeight)
|
|
341
|
+
: key
|
|
342
|
+
? qe.node_positions_by_key(networks, nUnits, nConnections, points, nUnits, nDims, nDims,
|
|
343
|
+
key.from, key.to, nCodes, selfWeight)
|
|
344
|
+
: qe.node_positions(networks, nUnits, nConnections, points, nUnits, nDims, nDims);
|
|
333
345
|
return {
|
|
334
346
|
nodes: new Float64Array(r.nodes.data),
|
|
335
347
|
nodeRows: r.nodes.rows,
|
package/src/tensor.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* tensor.js — Context-tensor accumulation for rENA WASM.
|
|
3
3
|
*
|
|
4
4
|
* Maps tma's apply_tensor() semantics to the JS/WASM layer. Each unit's
|
|
5
|
-
* network is accumulated by calling qe.
|
|
5
|
+
* network is accumulated by calling qe.accumulate_unit_networks() with a
|
|
6
6
|
* multi-dimensional tensor that encodes per-factor-combination window sizes
|
|
7
7
|
* and weights.
|
|
8
8
|
*
|
|
@@ -353,8 +353,8 @@ export function buildHorizonContexts(rows, unitOf, nUnits, horizons) {
|
|
|
353
353
|
* Accumulate tensor networks for all units across all conversations.
|
|
354
354
|
*
|
|
355
355
|
* Every accumulation — including plain windowed ENA, via defaultTensor(window)
|
|
356
|
-
* — runs through here,
|
|
357
|
-
*
|
|
356
|
+
* — runs through here, and the per-line finalisation (fold / binarize /
|
|
357
|
+
* weight / unit sum / self diagonal) happens in libtma.
|
|
358
358
|
*
|
|
359
359
|
* @param {object} qe libqe WASM module
|
|
360
360
|
* @param {Object[]} rows Full dataset
|
|
@@ -374,16 +374,28 @@ export function buildHorizonContexts(rows, unitOf, nUnits, horizons) {
|
|
|
374
374
|
* @param {object|null} [horizons=null] flexible horizons (see
|
|
375
375
|
* buildHorizonContexts); replaces
|
|
376
376
|
* convoGroups as the windowing contexts
|
|
377
|
+
* @param {boolean} [misses=true] also accumulate missed co-occurrences
|
|
378
|
+
* (ground i present, response j absent)
|
|
379
|
+
* @param {boolean} [diagonal=false] unordered only: self-connections are
|
|
380
|
+
* also connection columns (A & A, A & B,
|
|
381
|
+
* B & B, ...; n(n+1)/2 columns)
|
|
377
382
|
*
|
|
378
|
-
* @returns {{ networks: Float64Array, rowConnectionCounts: Float64Array
|
|
383
|
+
* @returns {{ networks: Float64Array, rowConnectionCounts: Float64Array,
|
|
384
|
+
* selfNetworks: Float64Array, missNetworks: Float64Array|null,
|
|
385
|
+
* selfMissNetworks: Float64Array|null }}
|
|
379
386
|
* networks nUnits × nConnections, row-major
|
|
380
387
|
* rowConnectionCounts nRows × nConnections, row-major — each row's finalised
|
|
381
388
|
* (folded / binarized / weighted) connection vector;
|
|
382
389
|
* rows sum by unit to `networks`
|
|
390
|
+
* selfNetworks nUnits × nCodes — self-connections (ground i ×
|
|
391
|
+
* response i, the ordered diagonal), weighted per line
|
|
392
|
+
* missNetworks nUnits × nConnections — missed co-occurrences (misses)
|
|
393
|
+
* selfMissNetworks nUnits × nCodes — self-misses (misses)
|
|
383
394
|
*/
|
|
384
395
|
export function accumulateTensor(qe, rows, codeMatrix, nRows, nCodes, nUnits,
|
|
385
396
|
unitOf, convoGroups, tensorDef, ordered = false,
|
|
386
|
-
binary = true, weight = null, horizons = null
|
|
397
|
+
binary = true, weight = null, horizons = null,
|
|
398
|
+
misses = true, diagonal = false) {
|
|
387
399
|
const {
|
|
388
400
|
dims,
|
|
389
401
|
dimsSender = [],
|
|
@@ -400,12 +412,16 @@ export function accumulateTensor(qe, rows, codeMatrix, nRows, nCodes, nUnits,
|
|
|
400
412
|
validateTensor(dims, tensorData, factors, factorLevels);
|
|
401
413
|
const allTimes = timesCol ? parseTimes(rows, timesCol, timesEndCol || null) : null;
|
|
402
414
|
|
|
415
|
+
const withDiagonal = diagonal && !ordered;
|
|
403
416
|
const nConnections = ordered
|
|
404
417
|
? nCodes * nCodes
|
|
405
|
-
: qe.choose_two(nCodes);
|
|
418
|
+
: withDiagonal ? (nCodes * (nCodes + 1)) / 2 : qe.choose_two(nCodes);
|
|
406
419
|
|
|
407
420
|
const networks = new Float64Array(nUnits * nConnections);
|
|
408
421
|
const rowConnectionCounts = new Float64Array(nRows * nConnections);
|
|
422
|
+
const selfNetworks = new Float64Array(nUnits * nCodes);
|
|
423
|
+
const missNetworks = misses ? new Float64Array(nUnits * nConnections) : null;
|
|
424
|
+
const selfMissNetworks = misses ? new Float64Array(nUnits * nCodes) : null;
|
|
409
425
|
|
|
410
426
|
// libqe weight argument: a weight-model name, or the legacy binary flag.
|
|
411
427
|
const kernelWeight = weight ?? binary;
|
|
@@ -435,40 +451,42 @@ export function accumulateTensor(qe, rows, codeMatrix, nRows, nCodes, nUnits,
|
|
|
435
451
|
? buildContextLookupWithTimes(rows, rowIndices, factors, factorLevels, allTimes)
|
|
436
452
|
: buildContextLookup(rows, rowIndices, factors, factorLevels);
|
|
437
453
|
|
|
438
|
-
//
|
|
439
|
-
//
|
|
440
|
-
//
|
|
441
|
-
//
|
|
442
|
-
|
|
443
|
-
// then double-count.
|
|
444
|
-
const result = qe.accumulate_tensor_unit(
|
|
454
|
+
// One libtma call (accumulate_unit_networks), as tma's accumulate()
|
|
455
|
+
// in R: fold (unordered), per-line weight model, unit sum and the
|
|
456
|
+
// self-connection diagonal, for hits and misses. Unit vectors are
|
|
457
|
+
// additive over lines, so a unit's contexts simply add up.
|
|
458
|
+
const args = [
|
|
445
459
|
tensorData, dimsArr,
|
|
446
460
|
senderArr, receiverArr, modeArr,
|
|
447
461
|
contextLookup, clRows, clCols,
|
|
448
462
|
new Int32Array(localRows),
|
|
449
463
|
ctxCodes, nCtx, nCodes,
|
|
450
464
|
times,
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
465
|
+
ordered, kernelWeight, misses,
|
|
466
|
+
];
|
|
467
|
+
// The trailing `diagonal` is an optional overload in libtma's binding.
|
|
468
|
+
const result = withDiagonal
|
|
469
|
+
? qe.accumulate_unit_networks(...args, true)
|
|
470
|
+
: qe.accumulate_unit_networks(...args);
|
|
471
|
+
const addUnit = (target, vec, width) => {
|
|
472
|
+
const off = unit * width;
|
|
473
|
+
for (let c = 0; c < width; c++) target[off + c] += vec[c];
|
|
474
|
+
};
|
|
475
|
+
addUnit(networks, result.connection_counts, nConnections);
|
|
476
|
+
addUnit(selfNetworks, result.self_connection_counts, nCodes);
|
|
477
|
+
if (misses) {
|
|
478
|
+
addUnit(missNetworks, result.miss_counts, nConnections);
|
|
479
|
+
addUnit(selfMissNetworks, result.self_miss_counts, nCodes);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Per-line weighted rows (rowConnectionCounts): libtma's weight_rows
|
|
483
|
+
// on the raw, already-folded rows. Row i is local row localRows[i].
|
|
459
484
|
const rcc = result.row_connection_counts;
|
|
460
|
-
const fin = qe.
|
|
461
|
-
rcc.data, rcc.rows, rcc.cols, nCodes, ordered, kernelWeight
|
|
462
|
-
);
|
|
463
|
-
const unitOff = unit * nConnections;
|
|
485
|
+
const fin = qe.weight_rows(rcc.data, rcc.rows, rcc.cols, ordered, kernelWeight);
|
|
464
486
|
for (let i = 0; i < fin.rows; i++) {
|
|
465
487
|
const rowOff = rowIndices[localRows[i]] * nConnections;
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
const v = fin.data[finOff + c];
|
|
469
|
-
rowConnectionCounts[rowOff + c] = v;
|
|
470
|
-
networks[unitOff + c] += v;
|
|
471
|
-
}
|
|
488
|
+
rowConnectionCounts.set(
|
|
489
|
+
fin.data.slice(i * fin.cols, (i + 1) * fin.cols), rowOff);
|
|
472
490
|
}
|
|
473
491
|
};
|
|
474
492
|
|
|
@@ -484,7 +502,7 @@ export function accumulateTensor(qe, rows, codeMatrix, nRows, nCodes, nUnits,
|
|
|
484
502
|
if (localRows.length) accumulateContext(rowIndices, unit, localRows);
|
|
485
503
|
}
|
|
486
504
|
});
|
|
487
|
-
return { networks, rowConnectionCounts };
|
|
505
|
+
return { networks, rowConnectionCounts, selfNetworks, missNetworks, selfMissNetworks };
|
|
488
506
|
}
|
|
489
507
|
|
|
490
508
|
for (const [, rowIndices] of convoGroups) {
|
|
@@ -503,7 +521,7 @@ export function accumulateTensor(qe, rows, codeMatrix, nRows, nCodes, nUnits,
|
|
|
503
521
|
}
|
|
504
522
|
}
|
|
505
523
|
|
|
506
|
-
return { networks, rowConnectionCounts };
|
|
524
|
+
return { networks, rowConnectionCounts, selfNetworks, missNetworks, selfMissNetworks };
|
|
507
525
|
}
|
|
508
526
|
|
|
509
527
|
/**
|