@qe-libs/rena-wasm 0.1.9 → 0.1.10

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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/index.js +27 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qe-libs/rena-wasm",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "JavaScript/WebAssembly ENA pipeline — thin orchestration layer over @qe-libs/libqe-wasm",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -31,7 +31,7 @@
31
31
  "resolver": "<rootDir>/jest-resolver.cjs"
32
32
  },
33
33
  "dependencies": {
34
- "@qe-libs/libqe-wasm": "^0.1.5"
34
+ "@qe-libs/libqe-wasm": "^0.1.6"
35
35
  },
36
36
  "devDependencies": {
37
37
  "jest": "^29.0.0"
package/src/index.js CHANGED
@@ -64,7 +64,7 @@ export { detectParams, isBinary, scoreUnit, scoreConvo } from './detect.js';
64
64
  * @param {number} dims
65
65
  * @returns {number[]} length dims, sums to 1
66
66
  */
67
- function computeVariance(points, nUnits, dims) {
67
+ function computeVariance(points, nUnits, dims, total = null) {
68
68
  if (nUnits < 2) return Array.from({ length: dims }, () => 1 / dims);
69
69
 
70
70
  // Column means
@@ -83,11 +83,29 @@ function computeVariance(points, nUnits, dims) {
83
83
  }
84
84
  for (let d = 0; d < dims; d++) variances[d] /= (nUnits - 1);
85
85
 
86
- const total = Array.from(variances).reduce((a, b) => a + b, 0);
86
+ if (total == null) total = Array.from(variances).reduce((a, b) => a + b, 0);
87
87
  if (total === 0) return Array.from({ length: dims }, () => 1 / dims);
88
88
  return Array.from(variances).map(v => v / total);
89
89
  }
90
90
 
91
+ /**
92
+ * Sum of the column sample variances of a row-major matrix (n-1 denominator,
93
+ * as R's var()).
94
+ */
95
+ function totalVariance(m, nRows, nCols) {
96
+ if (nRows < 2) return 0;
97
+ let total = 0;
98
+ for (let c = 0; c < nCols; c++) {
99
+ let mean = 0;
100
+ for (let r = 0; r < nRows; r++) mean += m[r * nCols + c];
101
+ mean /= nRows;
102
+ let ss = 0;
103
+ for (let r = 0; r < nRows; r++) { const d = m[r * nCols + c] - mean; ss += d * d; }
104
+ total += ss / (nRows - 1);
105
+ }
106
+ return total;
107
+ }
108
+
91
109
  /**
92
110
  * Build the adjacency key — list of [codeA, codeB] pairs for each connection.
93
111
  * Matches R's rotation$adjacency.key.
@@ -538,7 +556,13 @@ function runCustomRotation(qe, rawNetworks, lineWeights, ownCentered, ownCenterV
538
556
  nConnections,
539
557
  dims,
540
558
  centroids,
541
- variance: computeVariance(points, nUnits, dims),
559
+ // Share of the TOTAL variance, as R reports it with the full rotation
560
+ // matrix (ena.make.set: diag(var(points)) / sum over every dimension).
561
+ // A rotation is a complete basis, so that total is the variance of the
562
+ // centred, unrotated data -- which keeps the percentages right when the
563
+ // rotation set carries only the first few dimensions.
564
+ variance: computeVariance(points, nUnits, dims,
565
+ totalVariance(pointsForProjection, nUnits, nConnections)),
542
566
  unitLabels,
543
567
  pointsForProjection,
544
568
  nodes,