node-red-contrib-prib-functions 0.19.2 → 0.20.4

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 (75) hide show
  1. package/.github/workflows/codeql-analysis.yml +3 -3
  2. package/.github/workflows/npmpublish.yml +6 -6
  3. package/.vs/VSWorkspaceState.json +7 -0
  4. package/.vs/node-red-contrib-prib-functions/v17/.wsuo +0 -0
  5. package/README.md +6 -2
  6. package/arima/index.js +18 -0
  7. package/dataAnalysis/arrayAllRowsSwap.js +15 -0
  8. package/dataAnalysis/arrayCompareToPrecision.js +34 -0
  9. package/dataAnalysis/arrayDifference.js +14 -0
  10. package/dataAnalysis/arrayDifferenceSeasonal.js +15 -0
  11. package/dataAnalysis/arrayDifferenceSeasonalSecondOrder.js +20 -0
  12. package/dataAnalysis/arrayDifferenceSecondOrder.js +14 -0
  13. package/dataAnalysis/arrayForEachRange.js +38 -0
  14. package/dataAnalysis/arrayOverlay.js +13 -0
  15. package/dataAnalysis/arrayProduct.js +11 -0
  16. package/dataAnalysis/arrayRandom.js +14 -0
  17. package/dataAnalysis/arrayReduceRange.js +11 -0
  18. package/dataAnalysis/arrayScale.js +11 -0
  19. package/dataAnalysis/arraySum.js +11 -0
  20. package/dataAnalysis/arraySumSquared.js +11 -0
  21. package/dataAnalysis/arraySwap.js +11 -0
  22. package/dataAnalysis/dataAnalysis.html +31 -14
  23. package/dataAnalysis/dataAnalysis.js +10 -1
  24. package/dataAnalysis/generateMatrixFunction.js +89 -0
  25. package/dataAnalysis/generateVectorFunction.js +25 -0
  26. package/dataAnalysis/pca.js +472 -325
  27. package/dataAnalysis/svd.js +239 -0
  28. package/echart/echart.html +68 -0
  29. package/echart/echart.js +85 -0
  30. package/echart/icons/chart-671.png +0 -0
  31. package/echart/lib/echarts.js +95886 -0
  32. package/lib/Chart.js +177 -0
  33. package/lib/Column.js +99 -0
  34. package/lib/GraphDB.js +14 -0
  35. package/lib/Table.js +185 -0
  36. package/lib/objectExtensions.js +361 -0
  37. package/matrix/matrix.js +2 -48
  38. package/monitor/BarGauge.js +8 -0
  39. package/monitor/Dataset.js +29 -0
  40. package/monitor/DialGauge.js +109 -0
  41. package/monitor/DialNeedle.js +36 -0
  42. package/monitor/Format.js +74 -0
  43. package/monitor/centerElement.js +14 -0
  44. package/monitor/compareElements.js +95 -0
  45. package/monitor/defs.js +23 -0
  46. package/monitor/extensions.js +906 -0
  47. package/monitor/functions.js +36 -0
  48. package/monitor/json2xml.js +103 -0
  49. package/monitor/monitorSystem.html +198 -0
  50. package/monitor/monitorSystem.js +322 -0
  51. package/monitor/svgHTML.js +179 -0
  52. package/monitor/svgObjects.js +64 -0
  53. package/package.json +18 -6
  54. package/test/00-objectExtensions.js +94 -0
  55. package/test/04-tables.js +33 -0
  56. package/test/data/.config.nodes.json +608 -0
  57. package/test/data/.config.nodes.json.backup +608 -0
  58. package/test/data/.config.runtime.json +4 -0
  59. package/test/data/.config.runtime.json.backup +3 -0
  60. package/test/data/.config.users.json +21 -0
  61. package/test/data/.config.users.json.backup +21 -0
  62. package/test/data/.flow.json.backup +2448 -2207
  63. package/test/data/float32vector10.npy +0 -0
  64. package/test/data/flow.json +2412 -2191
  65. package/test/data/int2matrix2x3.npy +0 -0
  66. package/test/data/package-lock.json +158 -0
  67. package/test/data/package.json +11 -0
  68. package/test/dataAnalysisExtensions.js +472 -0
  69. package/test/dataAnalysisPCA.js +54 -0
  70. package/test/dataAnalysisSVD.js +31 -0
  71. package/test/euclideanDistance.js +2 -2
  72. package/test/transformNumPy.js +132 -0
  73. package/transform/NumPy.js +303 -0
  74. package/transform/transform.html +12 -0
  75. package/transform/transform.js +34 -2
@@ -1,32 +1,40 @@
1
- function PCA() {
1
+ require("./arrayAllRowsSwap");
2
+ require("./arrayForEachRange.js");
3
+ require("./arrayReduceRange.js");
4
+ require("./arrayScale.js");
5
+ require("./arraySwap.js");
6
+ require("./arraySum.js");
7
+ require("./arraySumSquared.js");
8
+ const generatedMatrixFunction = require("./generateMatrixFunction");
9
+ const generateVectorFunction=require("./generateVectorFunction.js")
10
+
11
+ function PCA() { //Principal Component Analysis
2
12
  }
3
- PCA.prototype.computeDeviationMatrix=function(matrix) {
4
- return this.subtract(matrix, this.scale(this.multiply(this.unitSquareMatrix(matrix.length), matrix), 1 / matrix.length));
13
+ PCA.prototype.rowType=Array;
14
+ PCA.prototype.getDeviationMatrix=function(matrix) {
15
+ const rows=matrix.length;
16
+ const onesMatrix=this.getMatrix(rows,rows,1);
17
+ const scaled=this.scale(this.multiply(onesMatrix, matrix),1/rows)
18
+ return this.subtract(matrix, scaled);
5
19
  }
6
- PCA.prototype.computeDeviationScores=function(deviation) {
7
- return this.multiply(this.transpose(deviation), deviation);
20
+ PCA.prototype.getDeviationScores=function(deviation) {
21
+ const transposed=this.transpose(deviation)
22
+ return this.multiply(transposed, deviation);
8
23
  }
9
- PCA.prototype.computeVarianceCovariance=function(devSumOfSquares, sample) {
10
- return this.scale(devSumOfSquares, 1 / (devSumOfSquares.length - sample?1:0));
24
+ PCA.prototype.getVarianceCovariance=function(devSumOfSquares, sample) {
25
+ return this.scale(devSumOfSquares, 1/devSumOfSquares.length);
11
26
  }
12
- PCA.prototype.computeSVD=function((atrix){
13
- const result = svd(matrix);
14
- const eigenvectors = result.U;
15
- const eigenvalues = result.S;
16
- return eigenvalues.map((value,i)=>{
17
- return {
18
- eigenvalue:value,
19
- vector:eigenvectors.map((vector,j)=>-vector[i]) //HACK prevent completely negative vectors
20
- }
21
- });
27
+ PCA.prototype.getVarianceCovarianceSample=function(devSumOfSquares) {
28
+ const factor=devSumOfSquares.length-1
29
+ return this.scale(devSumOfSquares, 1/factor);
22
30
  }
23
- // Get reduced dataset after removing some dimensions
24
- PCA.prototype.computeAdjustedData=function(data, ...vectorObjs){
31
+
32
+ PCA.prototype.getAdjustedData=function(data, ...vectorObjs){ // reduced after removing some dimensions
25
33
  const vectors = vectorObjs.map((v)=>v.vector);
26
- const matrixMinusMean = this.computeDeviationMatrix(data);
34
+ const matrixMinusMean = this.getDeviationMatrix(data);
27
35
  const adjustedData = this.multiply(vectors, this.transpose(matrixMinusMean));
28
- const unit = this.unitSquareMatrix(data.length);
29
- const avgData = this.scale(multiply(unit, data), -1 / data.length); //NOTE get the averages to add back
36
+ const rows=data.length
37
+ const avgData =this.scale(multiply(this.getMatrix(rows,rows,1),data), -1/rows); //NOTE get the averages to add back
30
38
  return {
31
39
  adjustedData: adjustedData,
32
40
  formattedAdjustedData:formatData(adjustedData, 2),
@@ -35,365 +43,504 @@ PCA.prototype.computeAdjustedData=function(data, ...vectorObjs){
35
43
  };
36
44
  }
37
45
  // Get original data set from reduced data set (decompress)
38
- PCA.prototype.computeOriginalData=function(adjustedData, vectors, avgData) {
46
+ PCA.prototype.getOriginalData=function(adjustedData, vectors, avgData) {
39
47
  const originalWithoutMean = this.transpose(multiply(transpose(vectors), adjustedData));
40
48
  const originalWithMean = this.subtract(originalWithoutMean, avgData);
41
49
  return {
42
50
  originalData: originalWithMean,
43
51
  formattedOriginalData: this.formatData(originalWithMean, 2)
44
52
  }
45
- PCA.prototype.computePercentageExplained=function(vectors, ...selected) {
46
- const total = vectors.map((v)=>v.eigenvalue).reduce((a,b)=>a+b);
47
- const explained = selected.map((v)=>v.eigenvalue).reduce((a,b)=>a+b);
53
+ }
54
+ PCA.prototype.getPercentageExplained=function(vectors, ...selected) {
55
+ const total = vectors.map((v)=>v.eigenvalue).sum();
56
+ const explained = selected.map((v)=>v.eigenvalue).sum();
48
57
  return (explained / total);
49
58
  }
50
59
  PCA.prototype.getEigenVectors=function(data) {
51
- return this.computeSVD(this.computeVarianceCovariance(this.computeDeviationScores(this.computeDeviationMatrix(data)), false));
60
+ const deviationMatrix=this.getDeviationMatrix(data);
61
+ const deviationScores=this.getDeviationScores(deviationMatrix)
62
+ const matrix=this.getVarianceCovariance(deviationScores)
63
+ const result = this.svd(matrix);
64
+ const eigenvectors = result.U;
65
+ const eigenvalues = result.S;
66
+ return eigenvalues.map((value,i)=>{
67
+ return {
68
+ eigenvalue:value,
69
+ vector:eigenvectors.map((vector,j)=>-vector[i]) //prevent completely negative vectors
70
+ }
71
+ });
52
72
  }
53
- PCA.prototype.analyseTopResult=function(data){
73
+ PCA.prototype.getTopResult=function(data){
54
74
  const eigenVectors = this.getEigenVectors(data);
55
- const sorted = this.eigenVectors.sort((a, b)=>b.eigenvalue-a.eigenvalue);
75
+ const sorted = eigenVectors.sort((a, b)=>b.eigenvalue-a.eigenvalue);
56
76
  const selected = sorted[0].vector;
57
- return this.computeAdjustedData(data, selected);
77
+ return this.getAdjustedData(data, selected);
58
78
  }
59
79
  PCA.prototype.formatData=function(data, precision) {
60
80
  const factor= Math.pow(10, precision || 2);
61
81
  return data.map((d,i)=>d.map((n)=>Math.round(n * factor) / factor))
62
82
  }
63
- PCA.prototype.testMatrix=function(a){
64
- if(!a[0] || !a.length) throw Error("Not matrix")
83
+ PCA.prototype.testIsMatrix=(a)=>{
84
+ if(!(a instanceof Array)) throw Error("Not matrix at row level, found type of "+typeof a)
85
+ const row=a[0];
86
+ if(row instanceof Array) return;
87
+ if(row instanceof this.rowType) return;
88
+ throw Error("Not matrix at column level, found type of "+typeof a[0])
65
89
  }
90
+ const sumVector1=generateVectorFunction({
91
+ code:"returnValue+=vector[index]*matrix[index][col]",
92
+ args:["matrix","col"],
93
+ returnValue:0
94
+ })
95
+ const multiplyMatrix=generatedMatrixFunction({
96
+ code:"setElement(sumVector1(element,bMatrix,columnOffset));",
97
+ args:["bMatrix"],
98
+ returnValue:"Object.create(Object.getPrototypeOf(matrix))"
99
+ })
100
+
66
101
  PCA.prototype.multiply=function(a, b){
67
- this.testMatrix(a);
68
- this.testMatrix(b);
69
- if(b.length !== a[0].length) throw new Error('Columns in A should be the same as the number of rows in B');
70
- const product = [];
71
- for(let i = 0; i < a.length; i++) {
72
- product[i] = []; //initialize a new row
73
- for (var j = 0; j < b[0].length; j++) {
74
- for (var k = 0; k < a[0].length; k++) {
75
- (product[i])[j] = !!(product[i])[j] ? (product[i])[j] + (a[i])[k] * (b[k])[j] : (a[i])[k] * (b[k])[j];
76
- }
102
+ this.testIsMatrix(a);
103
+ this.testIsMatrix(b);
104
+ const rows=a.length;
105
+ if(a[0].length !== b.length) throw Error("Non-conformable matrices, left columns: "+a[0].length+" != right rows "+b.length);
106
+ const columns=b[0].length;
107
+ const result=this.getMatrix(rows,columns);
108
+ for(let ri=0;ri<rows;ri++){
109
+ for(let ci=0;ci<columns;ci++){
110
+ result[ri][ci]=sumVector1(a[ri],b,ci);
111
+ // result[ri][ci]=a[ri].reduce((sum,value,rci)=>sum+value*b[rci][ci],0);
77
112
  }
78
113
  }
79
- return product;
114
+ return result
80
115
  }
116
+
81
117
  PCA.prototype.subtract=function(a,b) {
82
118
  if(!(a.length === b.length && a[0].length === b[0].length)) throw Error('Both A and B should have the same dimensions');
83
- const result=[];
84
- for(let i=0;i< a.length;i++){
85
- result[i]=[];
86
- for (let j = 0; j < b[0].length; j++) {
87
- (result[i])[j] = (a[i])[j] - (b[i])[j];
88
- }
119
+ const rows=a.length;
120
+ const columns=a[0].length;
121
+ const result=this.getMatrix(rows,columns);
122
+ for(let ri=0;ri<rows;ri++){
123
+ for(let ci=0;ci<columns;ci++){
124
+ result[ri][ci]=a[ri][ci]-b[ri][ci];
125
+ }
89
126
  }
90
- return result;
127
+ return result
91
128
  }
92
- PCA.prototype.scale=function(matrix, factor) {
93
- const result = [];
94
- for(let i = 0; i < matrix.length; i++) {
95
- result[i] = [];
96
- for(let j = 0; j < matrix[0].length; j++) {
97
- (result[i])[j] = (matrix[i])[j] * factor;
98
- }
129
+ function mapMatrix(matrix,callFunction) {
130
+ if(callFunction)
131
+ return matrix.map((row,ri)=>row.map((cell,ci)=>callFunction(cell,ri,ci,matrix)));
132
+ return this.cloneMatrix(matrix);
133
+ };
134
+
135
+ const mapVector=generateVectorFunction({
136
+ code:"vector[index]=fromVector[index]",
137
+ args:["fromVector"],
138
+ });
139
+
140
+ const cloneVector=generateVectorFunction({
141
+ code:"returnValue[index]=vector[index]",
142
+ args:["type=Array"],
143
+ });
144
+
145
+ function cloneMatrix(matrix){
146
+ const columns=matrix.length
147
+ const rows=matrix[0].length
148
+ const result=new Array(rows)
149
+ for(let ri=0;ri<rows;ri++){
150
+ const row=new this.rowType(columns);
151
+ mapVector(row,matrix[ri]);
152
+ result[ri]=row;
99
153
  }
100
154
  return result;
101
155
  }
102
- PCA.prototype.unitSquareMatrix=function(rows) {
103
- const result = [];
104
- for(let i = 0; i < rows; i++) {
105
- result[i] = [];
106
- for (var j = 0; j < rows; j++) {
107
- (result[i])[j] = 1;
108
- }
156
+ const transposeVector=generateVectorFunction({
157
+ code:"vector[index]=fromVector[index][column]",
158
+ args:["fromVector","column"],
159
+ });
160
+ //const mapVector=generateVectorFunction("returnValue[index]=vector[index]",[])
161
+ PCA.prototype.map=mapMatrix;
162
+ PCA.prototype.cloneMatrix=cloneMatrix;
163
+ PCA.prototype.mapTranspose=function(matrix) {
164
+ const columns=matrix.length
165
+ const rows=matrix[0].length
166
+ const result=new this.rowType(rows)
167
+ for(let ri=0;ri<rows;ri++){
168
+ const row=new this.rowType(columns);
169
+ transposeVector(row,matrix,ri)
170
+ result[ri]=row;
109
171
  }
110
172
  return result;
111
173
  }
112
- PCA.prototype.transpose=function(matrix) {
113
- const operated = this.clone(matrix);
114
- return operated[0].map((m,c)=>matrix.map((r)=>r[c]));
174
+ PCA.prototype.transpose=PCA.prototype.mapTranspose
175
+ PCA.prototype.forEachRow=function(matrix,callFunction) {
176
+ matrix.forEach(row,RowIndex=>callFunction(row,rowIndex,matrix))
177
+ return this
178
+ }
179
+ PCA.prototype.forEachRowColumn=function(matrix,rowIndex,callFunction) {
180
+ const row=matrix[rowIndex];
181
+ const columns=row[0].length;
182
+ for(let columnIndex=0;columnIndex<columns;columnIndex++)
183
+ callFunction(row[columnIndex],rowIndex,columnIndex,matrix)
184
+ return this
185
+ }
186
+
187
+ PCA.prototype.forEachColumn=function(matrix,columnIndex,callFunction) {
188
+ const rows=matrix.length;
189
+ for(let rowIndex=0;rowIndex<rows;rowIndex++)
190
+ callFunction(matrix[rowIndex][columnIndex],rowIndex,columnIndex,matrix)
191
+ return this
192
+ }
193
+ PCA.prototype.forEachCell=function(matrix,callFunction) {
194
+ const rows=matrix.length;
195
+ const columns=matrix[0].length;
196
+ for(let rowIndex=0;rowIndex<rows;rowIndex++){
197
+ const row=matrix[rowIndex];
198
+ for(let columnIndex=0;columnIndex<columns;columnIndex++)
199
+ callFunction(row[columnIndex],rowIndex,columnIndex,matrix)
200
+ }
201
+ return this
115
202
  }
116
- PCA.prototype.clone=function(m) {
117
- return m.map(r=>r.map(c=>c));
203
+ PCA.prototype.forEachSetCell=function(matrix,callFunction) {
204
+ const rows=matrix.length;
205
+ const columns=matrix[0].length;
206
+ for(let rowIndex=0;rowIndex<rows;rowIndex++){
207
+ const row=matrix[rowIndex];
208
+ for(let columnIndex=0;columnIndex<columns;columnIndex++)
209
+ row[columnIndex]=callFunction(rowIndex,columnIndex,cell,row,matrix)
210
+ }
211
+ return this
118
212
  }
119
- PCA.prototype.svd=function(A) {
120
- let temp;
121
- const prec = Math.pow(2, -52) // double presision
122
- const tolerance = 1.e-64 // precision;
123
- const itmax = 50;
124
- let c = 0;
125
- let i = 0;
126
- let j = 0;
127
- let k = 0;
128
- let l = 0;
129
- const u = this.clone(A);
130
- const m = u.length;
131
- const n = u[0].length;
132
- if (m < n) throw "Need more rows than columns"
213
+ PCA.prototype.scale=function(matrix,factor){return this.map(matrix,c=>c*factor)};
133
214
 
134
- const e = new Array(n); //vector1
135
- const q = new Array(n); //vector2
136
- for (i = 0; i < n; i++) e[i] = q[i] = 0.0;
137
- var v = rep([n, n], 0);
215
+ function getMatrix(rows=2,columns=rows,fill=0) {
216
+ const matrix=new Array(rows);
217
+ for(let i=0; i<rows; i++) matrix[i]=new this.rowType(columns).fill(fill);
218
+ return matrix;
219
+ }
138
220
 
139
- function pythag(a, b) {
140
- a = Math.abs(a)
141
- b = Math.abs(b)
142
- if(a > b) return a * Math.sqrt(1.0 + (b * b / a / a))
143
- if(b == 0.0) return a
144
- return b * Math.sqrt(1.0 + (a * a / b / b))
145
- }
146
- function rep(s, v, k=0) {
147
- const n=s[k],
148
- ret=Array(n);
149
- let i;
150
- if(k === s.length - 1) {
151
- for(i=n-2; i >= 0; i-=2) {
152
- ret[i+1] = v;
153
- ret[i] = v;
154
- }
155
- if(i === -1) ret[0] = v;
156
- return ret;
157
- }
158
- const kPlusOne=k++;
159
- for (i= n-1; i>=0; i--) {
160
- ret[i] = rep(s, v, kPlusOne);
161
- }
162
- return ret;
163
- }
164
- let f = 0.0;
165
- let g = 0.0;
166
- let h = 0.0;
167
- let x = 0.0;
168
- let y = 0.0;
169
- let z = 0.0;
170
- let s = 0.0;
221
+ PCA.prototype.getMatrix=getMatrix
171
222
 
172
- for(i=0; i<n; i++) {
173
- e[i] = g; //vector
174
- s = 0.0; //sum
175
- l = i+1; //stays i+1
176
- for(j=i; j<m; j++)
177
- s += (u[j][i] * u[j][i]);
178
- if(s <= tolerance)
179
- g = 0.0;
180
- else {
181
- f = u[i][i];
182
- g = Math.sqrt(s);
183
- if(f >= 0.0) g = -g;
184
- h = f * g - s
185
- u[i][i] = f - g;
186
- for(j=l; j<n; j++) {
187
- s = 0.0
188
- for(k=i; k < m; k++)
189
- s += u[k][i] * u[k][j]
190
- f = s / h
191
- for(k=i; k<m; k++)
192
- u[k][j] += f * u[k][i]
193
- }
223
+ PCA.prototype.pythag=(a,b)=>{
224
+ if(b == 0.0) return a
225
+ const a2 = a**2
226
+ const b2 = b**2
227
+ return a > b ? a * Math.sqrt(1.0 + b2/a2) : b * Math.sqrt(1.0 + a2/b2)
228
+ };
229
+ PCA.prototype.rep=function(s,v,k=0){
230
+ const n=s[k],returnVector=new this.rowType(n).fill(0);
231
+ if(k === s.length-1){
232
+ returnVector.fill(v,0,n-1)
233
+ } else {
234
+ const kPlusOne=k+1;
235
+ for(let i=n-1;i>=0;i--) returnVector[i]=this.rep(s,v,kPlusOne);
236
+ }
237
+ return returnVector;
238
+ }
239
+ module.exports = PCA;
240
+
241
+ PCA.prototype.getDeterminant=function(matrix){
242
+ const result = this.getDecomposed(matrix);
243
+ return result.lum.product()*result.toggle;
244
+ }
245
+ PCA.prototype.getDecomposed=function(matrix){
246
+ // Crout's LU decomposition for matrix determinant and inverse
247
+ // lum is lower & upper matrix
248
+ // perm is row permuations vector
249
+ const rows = matrix.length, rowsMinus1 = rows-1;
250
+ const perm = new this.rowType(rows).fill(0.0);
251
+ let toggle = +1; // even (+1) or odd (-1) row permutatuions
252
+ const result=Object.assign([],matrix);
253
+ const lum=Object.assign([],matrix);
254
+
255
+ for(let ri=0; ri<rows; ++ri) perm[ri]=ri
256
+ let piv=rows;
257
+ for(let j=0; j<rowsMinus1; ++j) {
258
+ const lumRowJ=lum[j];
259
+ let max = Math.abs(lumRowJ[j]);
260
+ for(let ri=j+1; ri<rows; ++ri) { // pivot index
261
+ const xrij = Math.abs(lum[ri][j]);
262
+ if(xrij > max) {
263
+ max = xrij;
264
+ piv = ri;
265
+ }
266
+ }
267
+
268
+ if(piv != j) {
269
+ lum.swap(piv,j)
270
+ perm.swap(piv,j);
271
+ toggle = -toggle;
272
+ }
273
+ const xjj = lumRowJ[j];
274
+ if(xjj !== 0.0) {
275
+ for(let i=j+1; i<rows; ++i) {
276
+ const lumRow=lum[i]
277
+ const xij = lumRow[j]/xjj;
278
+ lumRow[j] = xij;
279
+ for(let ci=0; ci<columns; ++ci) lumRow[ci] -= xij*lumRowJ[ci]
280
+ }
281
+ }
282
+ }
283
+ return {toggle:toggle,lum:lum,perm:perm}
284
+ }
285
+
286
+ PCA.prototype.getReduced=function(lum, b){
287
+ const rows = lum.length, rowsMinus1 = rows-1;
288
+ const x=new this.rowType(n).fill(0.0)
289
+ let sum;
290
+ for(let ri=0; ri<rows; ++ri) x[ri]=b[ri];
291
+ for(let ri=1; ri<rows; ++ri) {
292
+ const lumRow=lum[ri];
293
+ sum=x[ri];
294
+ for(let ci=0;ci<columns;ci++) sum-=lumRow[ci]*x[ci];
295
+ x[ri]=sum;
296
+ }
297
+ x[rowsMinus1] /= lum[rowsMinus1][rowsMinus1];
298
+ for (let ri=rows-2; ri>0; --ri) {
299
+ sum=x[ri];
300
+ for(let ci=0;ci<columns;ci++) sum-=lumRow[ci]*x[ci];
301
+ x[ri]=sum/lumRow[ri];
302
+ }
303
+ return x;
304
+ }
305
+
306
+ function svd(matrix) {//singular value decomposition
307
+ const eps=this.rowType instanceof Float64Array?
308
+ 2**-52:
309
+ this.rowType instanceof Float32Array?2**-23:Number.EPSILON;
310
+ let precision = eps;
311
+ const tolerance = 1.e-64;
312
+ const itmax = 50;
313
+ const rows=matrix.length
314
+ const rowOffsetEnd=rows-1;
315
+ const columns=matrix[0].length;
316
+ const columnOffsetEnd=columns-1;
317
+ if (rows < columns) throw "Need more rows than columns"
318
+ let temp;
319
+ let c= 0;
320
+ let i = 0;
321
+ let j = 0;
322
+ let k = 0;
323
+ let l = 0;
324
+ const u = this.cloneMatrix(matrix);
325
+ const e = new this.rowType(columns).fill(0.0); //vector1
326
+ const q = new this.rowType(columns).fill(0.0); //vector2
327
+ const v = this.rep([columns, columns], 0);
328
+ //Householder's reduction to bidiagonal form
329
+ let f = 0.0;
330
+ let g = 0.0;
331
+ let h = 0.0;
332
+ let x = 0.0;
333
+ let y = 0.0;
334
+ let z = 0.0;
335
+ let s = 0.0;
336
+
337
+ for(i=0; i<columns; i++) {
338
+ e[i] = g; //vector
339
+ const uRow=u[i]
340
+ const iPlus1=i+1;
341
+ const sum=u.reduceRange(i,rowOffsetEnd,(previousValue,row)=>previousValue+row[i]**2)
342
+ if(sum <= tolerance)
343
+ g = 0.0;
344
+ else {
345
+ f = uRow[i];
346
+ g = Math.sqrt(sum)*(f<0?1:-1);
347
+ h = f * g - sum
348
+ uRow[i] = f - g;
349
+ for(j=iPlus1; j<columns; j++) {
350
+ const factor=u.reduceRange(i,rowOffsetEnd,(previousValue,row)=>previousValue+row[i]*row[j])/h;
351
+ for(let ri=i;ri<=rowOffsetEnd;ri++) u[ri][j]+=factor*u[ri][i]
194
352
  }
195
- q[i] = g
196
- s = 0.0
197
- for(j=l; j<n; j++)
198
- s = s + u[i][j] * u[i][j]
199
- if (s <= tolerance)
200
- g = 0.0
201
- else {
202
- f = u[i][i + 1]
203
- g = Math.sqrt(s)
204
- if (f >= 0.0) g = -g
205
- h = f * g - s
206
- u[i][i + 1] = f - g;
207
- for(j=l; j < n; j++) e[j] = u[i][j] / h
208
- for(j=l; j < m; j++) {
209
- s = 0.0
210
- for(k=l; k<n; k++)
211
- s += (u[j][k] * u[i][k])
212
- for(k=l; k<n; k++)
213
- u[j][k] += s * e[k]
353
+ }
354
+ q[i] = g
355
+ const sumCols=u.reduceRange(iPlus1,columnOffsetEnd,(previousValue,cell,ci)=>previousValue+u[i][ci]**2)
356
+ if(sumCols <= tolerance)
357
+ g = 0.0
358
+ else {
359
+ f = uRow[iPlus1]
360
+ g = Math.sqrt(sumCols) * (f<0? 1:-1)
361
+ h = f * g - sumCols
362
+ uRow[iPlus1] = f - g;
363
+ for(let ci=iPlus1;ci<=columnOffsetEnd;ci++) e[ci]=uRow[ci]/h;
364
+ for(j = iPlus1; j < rows; j++) {
365
+ const uj=u[j];
366
+ const sum=uj.reduceRange(iPlus1,columnOffsetEnd,(previousValue,column,ci)=>previousValue+column*uRow[ci]);
367
+ for(let ci=iPlus1;ci<=columnOffsetEnd;ci++) uj[ci]+=sum*e[ci]; }
368
+ }
369
+ y = Math.abs(q[i]) + Math.abs(e[i])
370
+ if(y>x) x=y
371
+ }
372
+ l=columns;
373
+ // accumulation of right hand transformations
374
+ for(i=columnOffsetEnd; i != -1; i += -1) {
375
+ if (g != 0.0) {
376
+ const uRow=u[i]
377
+ h = g * uRow[i+1]
378
+ for(j=l; j<columns; j++)
379
+ v[j][i] = uRow[j] / h //u is array, v is square of columns
380
+ for(j=l; j < columns; j++) {
381
+ const sum=v.reduceRange(l,columnOffsetEnd,(previousValue,row,ri)=>previousValue+u[i][ri] * row[j])
382
+ for(let ci=l;ci<columns;ci++){
383
+ const vRow=v[ci];
384
+ vRow[j]+=vRow[i]*sum
214
385
  }
215
386
  }
216
- y = Math.abs(q[i]) + Math.abs(e[i])
217
- if(y > x)
218
- x = y
219
387
  }
388
+ const vRow=v[i]
389
+ for(j=l; j<columns; j++) {
390
+ vRow[j] = 0;
391
+ v[j][i] = 0;
392
+ }
393
+ vRow[i] = 1;
394
+ g = e[i]
395
+ l = i
396
+ }
220
397
 
221
- // accumulation of right hand transformations
222
- for(i = n-1; i!=-1; i--) {
223
- if (g != 0.0) {
224
- h = g * u[i][i + 1]
225
- for (j = l; j < n; j++)
226
- v[j][i] = u[i][j] / h //u is array, v is square of columns
227
- for (j = l; j < n; j++) {
228
- s = 0.0
229
- for (k = l; k < n; k++)
230
- s += u[i][k] * v[k][j]
231
- for (k = l; k < n; k++)
232
- v[k][j] += (s * v[k][i])
398
+ // accumulation of left hand transformations
399
+ for (i = columns - 1; i != -1; i += -1) {
400
+ l = i + 1
401
+ g = q[i]
402
+ const uRow=u[i];
403
+ for(j=l; j<columns; j++) uRow[j]=0;
404
+ if (g != 0.0)
405
+ for(let i=0;i<rows;i++) u[i][i];
406
+ else {
407
+ h = uRow[i] * g
408
+ for (j = l; j < columns; j++) {
409
+ const factor=u.reduceRange(l,rowOffsetEnd,(previousValue,row)=>previousValue+row[i]*row[j])/h;
410
+ for(let ci=i;ci<=rowOffsetEnd;ci++){
411
+ const row=u[ci];
412
+ row[j]+=row[i]*factor
233
413
  }
234
414
  }
235
- for (j = l; j < n; j++) {
236
- v[i][j] = 0;
237
- v[j][i] = 0;
238
- }
239
- v[i][i] = 1;
240
- g = e[i]
241
- l = i
242
- }
415
+ for(let ri=i;ri<=rowOffsetEnd;ri++) u[ri][i]/=g;
416
+ }
417
+ uRow[i]++;
418
+ }
243
419
 
244
- // accumulation of left hand transformations
245
- for(i=n-1; i != -1; i += -1) {
246
- l = i + 1
247
- g = q[i]
248
- for (j = l; j < n; j++)
249
- u[i][j] = 0;
250
- if (g != 0.0) {
251
- h = u[i][i] * g
252
- for (j = l; j < n; j++) {
253
- s = 0.0
254
- for (k = l; k < m; k++) s += u[k][i] * u[k][j];
255
- f = s / h
256
- for (k = i; k < m; k++) u[k][j] += f * u[k][i];
420
+ // diagonalization of the bidiagonal form
421
+ precision = precision * x;
422
+ for (k = columns - 1; k != -1; k += -1) {
423
+ for (var iteration = 0; iteration < itmax; iteration++) { // test f splitting
424
+ let test_convergence = false
425
+ for (l=k; l>=0; l--) {
426
+ if (Math.abs(e[l]) <= precision) {
427
+ test_convergence = true
428
+ break
257
429
  }
258
- for (j = i; j < m; j++) u[j][i] = u[j][i] / g;
259
- } else
260
- for (j = i; j < m; j++) u[j][i] = 0;
261
- u[i][i] += 1;
262
- }
263
-
264
- // diagonalization of the bidiagonal form
265
- prec = prec * x
266
- for(k=n-1; k != -1; k--) {
267
- const kPlusOne=k+1;
268
- const kMinusOne=k-1;
269
- for(let iteration = 0; iteration < itmax; iteration++) { // test f splitting
270
- let test_convergence = false
271
- for(l=k; l != -1; l--) {
272
- if(Math.abs(e[l]) <= prec) {
273
- test_convergence = true
430
+ if (Math.abs(q[l - 1]) <= precision)
431
+ break
432
+ }
433
+ if (!test_convergence) { // cancellation of e[l] if l>0
434
+ c = 0.0
435
+ s = 1.0
436
+ const l1 = l - 1
437
+ for(i=l; i<=k; i++) {
438
+ const ei=e[i];
439
+ f = s * ei
440
+ e[i] = c * ei
441
+ if (Math.abs(f) <= precision)
274
442
  break
443
+ g = q[i]
444
+ h = this.pythag(f, g)
445
+ q[i] = h
446
+ c = g / h
447
+ s = -f / h
448
+ for(let ci=l;ci<=columnOffsetEnd;ci++){
449
+ const row=u[ci];
450
+ const cl1 = row[l1]
451
+ const ci = row[i]
452
+ row[l1] = cl1 * c + (ci * s)
453
+ row[i] = -cl1 * s + (ci * c)
275
454
  }
276
- if (Math.abs(q[l - 1]) <= prec)
277
- break
278
455
  }
279
- if (!test_convergence) { // cancellation of e[l] if l>0
280
- c = 0.0
281
- s = 1.0
282
- const l1 = l - 1
283
- for(i=l; i<kPlusOne; i++) {
284
- f = s * e[i]
285
- e[i] = c * e[i]
286
- if (Math.abs(f) <= prec)
287
- break
288
- g = q[i]
289
- h = pythag(f, g)
290
- q[i] = h
291
- c = g / h
292
- s = -f / h
293
- for(j = 0; j<m; j++) {
294
- y = u[j][l1]
295
- z = u[j][i]
296
- u[j][l1] = y * c + (z * s)
297
- u[j][i] = -y * s + (z * c)
298
- }
299
- }
456
+ }
457
+ // test f convergence
458
+ z = q[k]
459
+ if(l == k) { //convergence
460
+ if(z < 0.0) { //q[k] is made non-negative
461
+ q[k] = -z
462
+ for(let ci=l;ci<=columnOffsetEnd;ci++) v[ci][k]*=-1;
300
463
  }
301
- // test f convergence
302
- z = q[k]
303
- if(l == k) { //convergence
304
- if(z < 0.0) { //q[k] is made non-negative
305
- q[k] = -z
306
- for (j=0; j<n; j++)
307
- v[j][k] = -v[j][k]
308
- }
309
- break //break out of iteration loop and move on to next k value
464
+ break //break out of iteration loop and move on to next k value
465
+ }
466
+ if(iteration >= itmax - 1)
467
+ throw 'Error: no convergence.'
468
+ // shift from bottom 2x2 minor
469
+ x = q[l]
470
+ const kMinus1=k-1;
471
+ y = q[kMinus1]
472
+ g = e[kMinus1]
473
+ h = e[k]
474
+ const z2=z**2
475
+ f = ((y**2 - z2 + g**2 - h*h)) / (2.0 * h * y)
476
+ g = this.pythag(f, 1.0)
477
+ const fg=f+f< 0.0?-g:g;
478
+ f = (x**2 - z2 + h * (y / fg - h)) / x
479
+ // next QR transformation
480
+ c = 1.0
481
+ s = 1.0
482
+ for(i=l+1; i <= k; i++) {
483
+ const iMinus1=i-1;
484
+ g = e[i]
485
+ y = q[i]
486
+ h = s * g
487
+ g = c * g
488
+ z = this.pythag(f, h)
489
+ e[iMinus1] = z
490
+ c = f / z
491
+ s = h / z
492
+ f = x * c + g * s
493
+ g = -x * s + g * c
494
+ h = y * s
495
+ y = y * c
496
+ for(j=0; j<columns; j++) {
497
+ const row=v[j];
498
+ x = row[iMinus1]
499
+ z = row[i]
500
+ row[iMinus1] = x * c + z * s
501
+ row[i] = -x * s + z * c
310
502
  }
311
- if (iteration >= itmax - 1)
312
- throw 'Error: no convergence.'
313
- // shift from bottom 2x2 minor
314
- x = q[l]
315
- y = q[kMinusOne]
316
- g = e[kMinusOne]
317
- h = e[k]
318
- f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y)
319
- g = pythag(f, 1.0)
320
- if(f < 0.0)
321
- f = ((x - z) * (x + z) + h * (y / (f - g) - h)) / x
322
- else
323
- f = ((x - z) * (x + z) + h * (y / (f + g) - h)) / x
324
- // next QR transformation
325
- c = 1.0
326
- s = 1.0
327
- for(i=l+1; i<kPlusOne; i++) {
328
- g = e[i]
329
- y = q[i]
330
- h = s * g
331
- g = c * g
332
- z = pythag(f, h)
333
- e[i - 1] = z
334
- c = f / z
335
- s = h / z
336
- f = x * c + g * s
337
- g = -x * s + g * c
338
- h = y * s
339
- y = y * c
340
- for (j = 0; j < n; j++) {
341
- x = v[j][i - 1]
342
- z = v[j][i]
343
- v[j][i - 1] = x * c + z * s
344
- v[j][i] = -x * s + z * c
345
- }
346
- z = pythag(f, h)
347
- q[i - 1] = z
348
- c = f / z
349
- s = h / z
350
- f = c * g + s * y
351
- x = -s * g + c * y
352
- for (j = 0; j < m; j++) {
353
- y = u[j][i - 1]
354
- z = u[j][i]
355
- u[j][i - 1] = y * c + z * s
356
- u[j][i] = -y * s + z * c
357
- }
503
+ z = this.pythag(f, h)
504
+ q[iMinus1] = z
505
+ c = f / z
506
+ s = h / z
507
+ f = c * g + s * y
508
+ x = -s * g + c * y
509
+ for(j=0; j<rows; j++) {
510
+ const row=u[j];
511
+ y = row[iMinus1]
512
+ z = row[i]
513
+ row[iMinus1] = y * c + z * s
514
+ row[i] = -y * s + z * c
358
515
  }
359
- e[l] = 0.0
360
- e[k] = f
361
- q[k] = x
362
516
  }
517
+ e[l] = 0.0
518
+ e[k] = f
519
+ q[k] = x
363
520
  }
364
- const ql=q.length;
365
- for(i=0; i<ql; i++)
366
- if (q[i] < prec) q[i] = 0
521
+ }
522
+ const ql=q.length;
523
+ for(i=0; i<ql; i++) if(q[i]<precision) q[i]=0;
367
524
 
368
- //sort eigenvalues
369
- for(i=0; i<n; i++) {
370
- for(j=i-1; j>=0; j--) {
371
- if(q[j] < q[i]) {
372
- c = q[j]
373
- q[j] = q[i]
374
- q[i] = c
375
- const ul=u.length;
376
- for(k = 0; k< ul; k++) {
377
- temp = u[k][i];
378
- u[k][i] = u[k][j];
379
- u[k][j] = temp;
380
- }
381
- const vl=v.length;
382
- for(k=0; k<vl; k++) {
383
- temp = v[k][i];
384
- v[k][i] = v[k][j];
385
- v[k][j] = temp;
386
- }
387
- i = j
388
- }
525
+ //sort eigenvalues
526
+ for(i=0; i<columns; i++) {
527
+ for(j=i-1; j>=0; j--) {
528
+ const qj=q[j];
529
+ const qi=q[i]
530
+ if(qj < qi) {
531
+ c = qj
532
+ q[j] = qi
533
+ q[i] = c
534
+ u.allRowsSwap(i,j);
535
+ v.allRowsSwap(i,j);
536
+ i=j
389
537
  }
390
538
  }
391
- return {
392
- U: u,
393
- S: q,
394
- V: v
395
- }
539
+ }
540
+ return {
541
+ U: u,
542
+ S: q,
543
+ V: v
396
544
  }
397
545
  }
398
-
399
- module.exports = PCA;
546
+ PCA.prototype.svd=svd;