node-red-contrib-prib-functions 0.17.0 → 0.19.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 CHANGED
@@ -3,6 +3,7 @@
3
3
  [Node-Red][1] nodes for various functions:
4
4
 
5
5
  * Data Analysis - statistical metrics that has real time option
6
+ * Matrix
6
7
  * Transform
7
8
  * Test
8
9
  * Load Injector
@@ -66,6 +67,36 @@ example:
66
67
 
67
68
  ![Data Analysis example](documentation/DataAnalysisTest.JPG "Data Analysis example")
68
69
 
70
+
71
+ ------------------------------------------------------------
72
+
73
+ ## Matrix
74
+
75
+ Define a matrix and perform various functions
76
+
77
+ * Define / Define Empty / Create / Create Like/ clone"
78
+ * Add / Add Row to Row / Add to Cell / Add Row / Subtract Cell
79
+ * Multiple / Multiple Cell / Divide Cell / Divide Row
80
+ * Transpose
81
+ * Adjoint
82
+ * Cofactor
83
+ * Complement Minor
84
+ * Identity
85
+ * Inverse
86
+ * Determinant
87
+ * Backward Substitution
88
+ * Forward Elimination
89
+ * Gaussian Elimination
90
+ * Reduced Row EchelonForm
91
+ * Row Echelon Form
92
+ * Nearly Equals / Is Square / Get Cell
93
+ * Sum Row
94
+ * Swap Rows
95
+ * To Array Object
96
+
97
+
98
+ ![Matrix](documentation/matrix.jpg "Matrix")
99
+
69
100
  ------------------------------------------------------------
70
101
 
71
102
  ## Transform
@@ -80,8 +111,12 @@ Transformations:
80
111
  * Array to ISO8385
81
112
  * Array to Messages
82
113
  * Array to xlsx / xlsx object (excel uses [xlsx][7])
83
- * AVRO to JSON (uses [avsc][6])
114
+ * AVRO to JSON (uses [avsc][6])
115
+ * Buffer to comprossed
84
116
  * Confluence to JSON
117
+ * Compressed to Buffer
118
+ * Compressed to String
119
+ * COmpressed to JSON
85
120
  * CSV to Array
86
121
  * CSV to HTML
87
122
  * CSV to Messages
@@ -120,7 +155,7 @@ With xlsx object one can use the function in [xlsx][7] against the object in fun
120
155
 
121
156
  Example AVRO with schema
122
157
 
123
- ![Transform AVRO](documentation/transformArvo.JPG "Transform AVRO example")
158
+ ![Transform AVRO](documentation/transformArvo.jpg "Transform AVRO example")
124
159
 
125
160
  For Confluence schema contains a list of schemas in form {"<schema id>",<schema>}
126
161
 
@@ -168,7 +203,13 @@ The levenshtein distance between two character strings.
168
203
  Inject messages for a set period of time with varying think time.
169
204
  Primary purpose is testing and useful for load/stress testing.
170
205
 
171
- ![Load Injector](documentation/LoadInjector.JPG "Load Injector")
206
+ Has 3 extra data types
207
+ 1. generated id - Unique id for each message
208
+ 2. generated data - string text generated using [dummy-json][3]
209
+ 3. generated json - json generated using [dummy-json][3]
210
+
211
+
212
+ ![Load Injector](documentation/loadInjector.png "Load Injector")
172
213
 
173
214
  Test example:
174
215
 
@@ -247,25 +288,14 @@ Test/example flow in test/generalTest.json
247
288
 
248
289
  # Version
249
290
 
250
- 0.17.0 Add finished wire to load injector
251
-
252
- 0.16.10 data analysis add eulcidean distance functions. Add array pairs
291
+ 0.19.0 Improve load injector, fix bug in test comparing buffers, add compression tranforms
253
292
 
254
- 0.16.0 fix data analysis variance and stddev, add sample, add tests
255
-
256
- 0.14.2 fix general test flows. Add icon for data analysis
257
-
258
- 0.14.1 fix capitalization issue with levenshtein Distance
259
-
260
- 0.14.0 add xlsx transformer
293
+ 0.18.0 Add matrix node
261
294
 
262
- 0.13.0 Confluence AVRO message converter
263
-
264
- 0.12.0 added xml to json and json to xml. Make snappy installed separately as can cause install issues
295
+ 0.17.0 Add finished wire to load injector
265
296
 
266
- 0.11.1 Fix spelling of AVRO.
297
+ 0.16.0 fix data analysis variance and stddev, add sample, add tests
267
298
 
268
- 0.11.0 Transform for AVRO and snappy. Add JSON to CSV
269
299
 
270
300
 
271
301
  # Author
@@ -285,3 +315,5 @@ Test/example flow in test/generalTest.json
285
315
  [6]: https://www.npmjs.com/package/avsc "avsc"
286
316
 
287
317
  [7]: https://www.npmjs.com/package/xlsx "xlsx"
318
+
319
+ [8]: https://www.npmjs.com/package/dummy-json "dummy-json"
@@ -0,0 +1,399 @@
1
+ function PCA() {
2
+ }
3
+ PCA.prototype.computeDeviationMatrix=function(matrix) {
4
+ return this.subtract(matrix, this.scale(this.multiply(this.unitSquareMatrix(matrix.length), matrix), 1 / matrix.length));
5
+ }
6
+ PCA.prototype.computeDeviationScores=function(deviation) {
7
+ return this.multiply(this.transpose(deviation), deviation);
8
+ }
9
+ PCA.prototype.computeVarianceCovariance=function(devSumOfSquares, sample) {
10
+ return this.scale(devSumOfSquares, 1 / (devSumOfSquares.length - sample?1:0));
11
+ }
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
+ });
22
+ }
23
+ // Get reduced dataset after removing some dimensions
24
+ PCA.prototype.computeAdjustedData=function(data, ...vectorObjs){
25
+ const vectors = vectorObjs.map((v)=>v.vector);
26
+ const matrixMinusMean = this.computeDeviationMatrix(data);
27
+ 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
30
+ return {
31
+ adjustedData: adjustedData,
32
+ formattedAdjustedData:formatData(adjustedData, 2),
33
+ avgData: avgData,
34
+ selectedVectors: vectors
35
+ };
36
+ }
37
+ // Get original data set from reduced data set (decompress)
38
+ PCA.prototype.computeOriginalData=function(adjustedData, vectors, avgData) {
39
+ const originalWithoutMean = this.transpose(multiply(transpose(vectors), adjustedData));
40
+ const originalWithMean = this.subtract(originalWithoutMean, avgData);
41
+ return {
42
+ originalData: originalWithMean,
43
+ formattedOriginalData: this.formatData(originalWithMean, 2)
44
+ }
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);
48
+ return (explained / total);
49
+ }
50
+ PCA.prototype.getEigenVectors=function(data) {
51
+ return this.computeSVD(this.computeVarianceCovariance(this.computeDeviationScores(this.computeDeviationMatrix(data)), false));
52
+ }
53
+ PCA.prototype.analyseTopResult=function(data){
54
+ const eigenVectors = this.getEigenVectors(data);
55
+ const sorted = this.eigenVectors.sort((a, b)=>b.eigenvalue-a.eigenvalue);
56
+ const selected = sorted[0].vector;
57
+ return this.computeAdjustedData(data, selected);
58
+ }
59
+ PCA.prototype.formatData=function(data, precision) {
60
+ const factor= Math.pow(10, precision || 2);
61
+ return data.map((d,i)=>d.map((n)=>Math.round(n * factor) / factor))
62
+ }
63
+ PCA.prototype.testMatrix=function(a){
64
+ if(!a[0] || !a.length) throw Error("Not matrix")
65
+ }
66
+ 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
+ }
77
+ }
78
+ }
79
+ return product;
80
+ }
81
+ PCA.prototype.subtract=function(a,b) {
82
+ 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
+ }
89
+ }
90
+ return result;
91
+ }
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
+ }
99
+ }
100
+ return result;
101
+ }
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
+ }
109
+ }
110
+ return result;
111
+ }
112
+ PCA.prototype.transpose=function(matrix) {
113
+ const operated = this.clone(matrix);
114
+ return operated[0].map((m,c)=>matrix.map((r)=>r[c]));
115
+ }
116
+ PCA.prototype.clone=function(m) {
117
+ return m.map(r=>r.map(c=>c));
118
+ }
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"
133
+
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);
138
+
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;
171
+
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
+ }
194
+ }
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]
214
+ }
215
+ }
216
+ y = Math.abs(q[i]) + Math.abs(e[i])
217
+ if(y > x)
218
+ x = y
219
+ }
220
+
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])
233
+ }
234
+ }
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
+ }
243
+
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];
257
+ }
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
274
+ break
275
+ }
276
+ if (Math.abs(q[l - 1]) <= prec)
277
+ break
278
+ }
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
+ }
300
+ }
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
310
+ }
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
+ }
358
+ }
359
+ e[l] = 0.0
360
+ e[k] = f
361
+ q[k] = x
362
+ }
363
+ }
364
+ const ql=q.length;
365
+ for(i=0; i<ql; i++)
366
+ if (q[i] < prec) q[i] = 0
367
+
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
+ }
389
+ }
390
+ }
391
+ return {
392
+ U: u,
393
+ S: q,
394
+ V: v
395
+ }
396
+ }
397
+ }
398
+
399
+ module.exports = PCA;
Binary file