node-red-contrib-prib-functions 0.18.0 → 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 (87) 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 +22 -19
  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 +546 -0
  27. package/dataAnalysis/svd.js +239 -0
  28. package/documentation/loadInjector.png +0 -0
  29. package/echart/echart.html +68 -0
  30. package/echart/echart.js +85 -0
  31. package/echart/icons/chart-671.png +0 -0
  32. package/echart/lib/echarts.js +95886 -0
  33. package/lib/Chart.js +177 -0
  34. package/lib/Column.js +99 -0
  35. package/lib/GraphDB.js +14 -0
  36. package/lib/Table.js +185 -0
  37. package/lib/objectExtensions.js +361 -0
  38. package/matrix/matrix.js +50 -50
  39. package/matrix/matrixNode.html +144 -154
  40. package/matrix/matrixNode.js +26 -9
  41. package/monitor/BarGauge.js +8 -0
  42. package/monitor/Dataset.js +29 -0
  43. package/monitor/DialGauge.js +109 -0
  44. package/monitor/DialNeedle.js +36 -0
  45. package/monitor/Format.js +74 -0
  46. package/monitor/centerElement.js +14 -0
  47. package/monitor/compareElements.js +95 -0
  48. package/monitor/defs.js +23 -0
  49. package/monitor/extensions.js +906 -0
  50. package/monitor/functions.js +36 -0
  51. package/monitor/json2xml.js +103 -0
  52. package/monitor/monitorSystem.html +198 -0
  53. package/monitor/monitorSystem.js +322 -0
  54. package/monitor/svgHTML.js +179 -0
  55. package/monitor/svgObjects.js +64 -0
  56. package/package.json +31 -8
  57. package/test/00-objectExtensions.js +94 -0
  58. package/test/01-base.js +88 -0
  59. package/test/04-tables.js +33 -0
  60. package/test/data/.config.nodes.json +608 -0
  61. package/test/data/.config.nodes.json.backup +608 -0
  62. package/test/data/.config.runtime.json +4 -0
  63. package/test/data/.config.runtime.json.backup +3 -0
  64. package/test/data/.config.users.json +21 -0
  65. package/test/data/.config.users.json.backup +21 -0
  66. package/test/data/.flow.json.backup +3433 -0
  67. package/test/data/float32vector10.npy +0 -0
  68. package/test/data/flow.json +3433 -0
  69. package/test/data/int2matrix2x3.npy +0 -0
  70. package/test/data/package-lock.json +158 -0
  71. package/test/data/package.json +11 -0
  72. package/test/data/settings.js +544 -0
  73. package/test/dataAnalysisExtensions.js +472 -0
  74. package/test/dataAnalysisPCA.js +54 -0
  75. package/test/dataAnalysisSVD.js +31 -0
  76. package/test/euclideanDistance.js +2 -2
  77. package/test/matrix/02base.js +36 -0
  78. package/test/transformNumPy.js +132 -0
  79. package/testing/data/countries.csv +250 -0
  80. package/testing/hostAvailable.html +0 -2
  81. package/testing/load-injector.html +76 -21
  82. package/testing/load-injector.js +35 -54
  83. package/testing/test.js +1 -0
  84. package/transform/NumPy.js +303 -0
  85. package/transform/transform.html +73 -19
  86. package/transform/transform.js +144 -8
  87. package/documentation/LoadInjector.JPG +0 -0
@@ -0,0 +1,89 @@
1
+ function generatedMatrixFunction(arg1) {
2
+ if(typeof arg1 !=="object") throw Error("no definitional JSON found");
3
+ Object.assign(this,{
4
+ args:[],
5
+ dimensionOrder:["row","column"],
6
+ returnValue:"this",
7
+ debug:false
8
+ },arg1);
9
+ const extendedArgs=[
10
+ this.dimensionOrder[0]+"StartOffset=0",
11
+ this.dimensionOrder[0]+"EndOffset",
12
+ this.dimensionOrder[1]+"StartOffset=0",
13
+ this.dimensionOrder[1]+"EndOffset",
14
+ "returnValue="+this.returnValue,
15
+ "matrixEndOffset=matrix.length-1",
16
+ "rowOffset",
17
+ "columnOffset",
18
+ "rowVectorOffset",
19
+ "columnVectorOffset",
20
+ "elementOffset",
21
+ "element",
22
+ "getElementArray=()=>matrix[rowOffset][columnOffset]",
23
+ "getElementVector=()=>matrix[elementOffset]",
24
+ "setElementArray=(v)=>matrix[rowOffset][columnOffset]=v",
25
+ "setElementVector=(v)=>matrix[elementOffset]=v",
26
+ "getElement=getElementVector",
27
+ "setElement=setElementVector",
28
+ "getMatrix=()=>Object.create(Object.getPrototypeOf(matrix))",
29
+ "arrayFunctions={"+
30
+ "forEachRowColumn:(call)=>{for(rowOffset=0;rowOffset<=rowEndOffset;rowOffset++) call()},"+
31
+ "forEachColumnRow:(call)=>{for(columnOffset=0;columnOffset<=columnEndOffset;columnOffset++) call()}"+
32
+ "}",
33
+ "vectorFunctions={}"
34
+ ];
35
+ const functionCode=
36
+ "("+["matrix","rows",
37
+ "columns"
38
+ ].concat(this.args,extendedArgs).join()+
39
+ ")=>{\n"+
40
+ " const isArray=(matrix!==null&&matrix instanceof Array)\n"+
41
+ " if(isArray){\n"+
42
+ " rows=matrix.length\n"+
43
+ " columns=matrix[0].length\n"+
44
+ " getElement=getElementArray\n"+
45
+ " setElement=setElementArray\n"+
46
+ " }\n"+
47
+ " if(rows<=0) throw Error('rows < 1')\n"+
48
+ " if(columns<=0) throw Error('rows < 1')\n"+
49
+ " if(rowEndOffset==null) rowEndOffset=rows-1\n"+
50
+ " if(columnEndOffset==null) columnEndOffset=columns-1\n"+
51
+ (this.debug?"console.log({matrix:matrix,matrixEndOffset:matrixEndOffset,rowEndOffset:rowEndOffset,columnEndOffset:columnEndOffset,rows:rows,columns:columns})\n":"")+
52
+ " if(isArray){\n"+
53
+ " for("+this.dimensionOrder[0]+"Offset="+this.dimensionOrder[0]+"StartOffset;"+this.dimensionOrder[0]+"Offset<="+this.dimensionOrder[0]+"EndOffset;"+this.dimensionOrder[0]+"Offset++){\n"+
54
+ " const "+this.dimensionOrder[0]+"=matrix["+this.dimensionOrder[0]+"Offset]\n"+
55
+ (this.debug?"console.log({"+this.dimensionOrder[0]+"Offset:"+this.dimensionOrder[0]+"Offset,})\n":"")+"\n"+
56
+ " for("+this.dimensionOrder[1]+"Offset="+this.dimensionOrder[1]+"StartOffset;"+this.dimensionOrder[1]+"Offset<="+this.dimensionOrder[1]+"EndOffset;"+this.dimensionOrder[1]+"Offset++){\n"+
57
+ " const element=matrix["+this.dimensionOrder[1]+"Offset]\n"+
58
+ (this.debug?"console.log({"+this.dimensionOrder[1]+"Offset:"+this.dimensionOrder[1]+"Offset,element:element})\n":"")+
59
+ this.code+"\n"+
60
+ " }\n"+
61
+ " }\n"+
62
+ " } else {\n"+
63
+ " const innerSize="+(this.dimensionOrder[0]=="row"?"columns":"1")+"\n"+
64
+ " const outerSize="+(this.dimensionOrder[0]=="row"?"1":"columns")+"\n"+
65
+ " for("+this.dimensionOrder[0]+"Offset="+this.dimensionOrder[0]+"StartOffset;"+this.dimensionOrder[0]+"Offset<="+this.dimensionOrder[0]+"EndOffset;"+this.dimensionOrder[0]+"Offset++){\n"+
66
+ " const "+this.dimensionOrder[0]+"VectorOffset="+this.dimensionOrder[0]+"Offset*innerSize\n"+
67
+ (debug?"console.log({"+this.dimensionOrder[0]+"Offset:"+this.dimensionOrder[0]+"Offset,})\n":"")+
68
+ " for("+this.dimensionOrder[1]+"Offset="+this.dimensionOrder[1]+"StartOffset;"+this.dimensionOrder[1]+"Offset<="+this.dimensionOrder[1]+"EndOffset;"+this.dimensionOrder[1]+"Offset++){\n"+
69
+ " "+this.dimensionOrder[1]+"VectorOffset="+this.dimensionOrder[1]+"Offset*outerSize\n"+
70
+ " elementOffset=rowVectorOffset +columnOffset\n"+
71
+ " element=matrix[elementOffset];\n"+
72
+ (debug?"console.log({"+this.dimensionOrder[1]+"Offset:"+this.dimensionOrder[1]+"Offset,rowVectorOffset:rowVectorOffset,columnVectorOffset:columnVectorOffset,elementOffset:elementOffset,element:element})\n":"")+
73
+ " "+this.code+"\n"+
74
+ " }\n"+
75
+ " }\n"+
76
+ " }\n"+
77
+ (this.returnValue==undefined?" return this":" return returnValue")+
78
+ "\n}";
79
+ try{
80
+ const evaluatedCode=eval(functionCode);
81
+ return evaluatedCode;
82
+ } catch(ex) {
83
+ console.error("built function: \n"+functionCode)
84
+ console.error("error: "+ex.message)
85
+ console.error(ex.stack)
86
+ throw Error("code failed")
87
+ }
88
+ }
89
+ module.exports = generatedMatrixFunction;
@@ -0,0 +1,25 @@
1
+ function generatedVectorFunction(arg1) {
2
+ if(typeof arg1 !=="object") throw Error("no definitional JSON found");
3
+ Object.assign(this,{
4
+ args:[],
5
+ debug:false,
6
+ returnValue:"this"
7
+ },arg1);
8
+ const extendedArgs=["startOffset=0","endOffset=vector.length-1,returnValue="+this.returnValue]
9
+ const functionCode=
10
+ "("+["vector"].concat(this.args,extendedArgs).join()+")=>{"+
11
+ "for(let index=startOffset;index<=endOffset;index++){\n"+
12
+ this.code+";\n"+
13
+ "}\n"+
14
+ "return returnValue\n}";
15
+ try{
16
+ if(debug==true) console.log(functionCode);
17
+ const evaluatedCode=eval(functionCode);
18
+ return evaluatedCode;
19
+ } catch(ex) {
20
+ console.error("built function: "+functionCode)
21
+ console.error("error: "+ex.message)
22
+ throw Error("code failed")
23
+ }
24
+ }
25
+ module.exports = generatedVectorFunction;
@@ -0,0 +1,546 @@
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
12
+ }
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);
19
+ }
20
+ PCA.prototype.getDeviationScores=function(deviation) {
21
+ const transposed=this.transpose(deviation)
22
+ return this.multiply(transposed, deviation);
23
+ }
24
+ PCA.prototype.getVarianceCovariance=function(devSumOfSquares, sample) {
25
+ return this.scale(devSumOfSquares, 1/devSumOfSquares.length);
26
+ }
27
+ PCA.prototype.getVarianceCovarianceSample=function(devSumOfSquares) {
28
+ const factor=devSumOfSquares.length-1
29
+ return this.scale(devSumOfSquares, 1/factor);
30
+ }
31
+
32
+ PCA.prototype.getAdjustedData=function(data, ...vectorObjs){ // reduced after removing some dimensions
33
+ const vectors = vectorObjs.map((v)=>v.vector);
34
+ const matrixMinusMean = this.getDeviationMatrix(data);
35
+ const adjustedData = this.multiply(vectors, this.transpose(matrixMinusMean));
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
38
+ return {
39
+ adjustedData: adjustedData,
40
+ formattedAdjustedData:formatData(adjustedData, 2),
41
+ avgData: avgData,
42
+ selectedVectors: vectors
43
+ };
44
+ }
45
+ // Get original data set from reduced data set (decompress)
46
+ PCA.prototype.getOriginalData=function(adjustedData, vectors, avgData) {
47
+ const originalWithoutMean = this.transpose(multiply(transpose(vectors), adjustedData));
48
+ const originalWithMean = this.subtract(originalWithoutMean, avgData);
49
+ return {
50
+ originalData: originalWithMean,
51
+ formattedOriginalData: this.formatData(originalWithMean, 2)
52
+ }
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();
57
+ return (explained / total);
58
+ }
59
+ PCA.prototype.getEigenVectors=function(data) {
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
+ });
72
+ }
73
+ PCA.prototype.getTopResult=function(data){
74
+ const eigenVectors = this.getEigenVectors(data);
75
+ const sorted = eigenVectors.sort((a, b)=>b.eigenvalue-a.eigenvalue);
76
+ const selected = sorted[0].vector;
77
+ return this.getAdjustedData(data, selected);
78
+ }
79
+ PCA.prototype.formatData=function(data, precision) {
80
+ const factor= Math.pow(10, precision || 2);
81
+ return data.map((d,i)=>d.map((n)=>Math.round(n * factor) / factor))
82
+ }
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])
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
+
101
+ PCA.prototype.multiply=function(a, b){
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);
112
+ }
113
+ }
114
+ return result
115
+ }
116
+
117
+ PCA.prototype.subtract=function(a,b) {
118
+ if(!(a.length === b.length && a[0].length === b[0].length)) throw Error('Both A and B should have the same dimensions');
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
+ }
126
+ }
127
+ return result
128
+ }
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;
153
+ }
154
+ return result;
155
+ }
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;
171
+ }
172
+ return result;
173
+ }
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
202
+ }
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
212
+ }
213
+ PCA.prototype.scale=function(matrix,factor){return this.map(matrix,c=>c*factor)};
214
+
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
+ }
220
+
221
+ PCA.prototype.getMatrix=getMatrix
222
+
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]
352
+ }
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
385
+ }
386
+ }
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
+ }
397
+
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
413
+ }
414
+ }
415
+ for(let ri=i;ri<=rowOffsetEnd;ri++) u[ri][i]/=g;
416
+ }
417
+ uRow[i]++;
418
+ }
419
+
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
429
+ }
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)
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)
454
+ }
455
+ }
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;
463
+ }
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
502
+ }
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
515
+ }
516
+ }
517
+ e[l] = 0.0
518
+ e[k] = f
519
+ q[k] = x
520
+ }
521
+ }
522
+ const ql=q.length;
523
+ for(i=0; i<ql; i++) if(q[i]<precision) q[i]=0;
524
+
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
537
+ }
538
+ }
539
+ }
540
+ return {
541
+ U: u,
542
+ S: q,
543
+ V: v
544
+ }
545
+ }
546
+ PCA.prototype.svd=svd;