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

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 (82) 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 +84 -70
  6. package/dataAnalysis/arrayAllRowsSwap.js +15 -0
  7. package/dataAnalysis/arrayCompareToPrecision.js +34 -0
  8. package/dataAnalysis/arrayDifference.js +14 -0
  9. package/dataAnalysis/arrayDifferenceSeasonal.js +15 -0
  10. package/dataAnalysis/arrayDifferenceSeasonalSecondOrder.js +20 -0
  11. package/dataAnalysis/arrayDifferenceSecondOrder.js +14 -0
  12. package/dataAnalysis/arrayForEachRange.js +38 -0
  13. package/dataAnalysis/arrayOverlay.js +13 -0
  14. package/dataAnalysis/arrayProduct.js +11 -0
  15. package/dataAnalysis/arrayRandom.js +14 -0
  16. package/dataAnalysis/arrayReduceRange.js +11 -0
  17. package/dataAnalysis/arrayScale.js +11 -0
  18. package/dataAnalysis/arraySum.js +11 -0
  19. package/dataAnalysis/arraySumSquared.js +11 -0
  20. package/dataAnalysis/arraySwap.js +11 -0
  21. package/dataAnalysis/dataAnalysis.html +52 -21
  22. package/dataAnalysis/dataAnalysis.js +73 -44
  23. package/dataAnalysis/generateMatrixFunction.js +89 -0
  24. package/dataAnalysis/generateVectorFunction.js +25 -0
  25. package/dataAnalysis/pca.js +472 -325
  26. package/dataAnalysis/svd.js +239 -0
  27. package/documentation/DataAnalysisRealtime.JPG +0 -0
  28. package/documentation/monitorSystem.JPG +0 -0
  29. package/documentation/monitorSystemTest.JPG +0 -0
  30. package/echart/echart.html +68 -0
  31. package/echart/echart.js +85 -0
  32. package/echart/icons/chart-671.png +0 -0
  33. package/echart/lib/echarts.js +95886 -0
  34. package/lib/Chart.js +177 -0
  35. package/lib/Column.js +99 -0
  36. package/lib/GraphDB.js +14 -0
  37. package/lib/Table.js +185 -0
  38. package/lib/objectExtensions.js +361 -0
  39. package/matrix/matrix.js +95 -56
  40. package/matrix/matrixNode.html +88 -55
  41. package/matrix/matrixNode.js +12 -5
  42. package/monitor/BarGauge.js +8 -0
  43. package/monitor/Dataset.js +29 -0
  44. package/monitor/DialGauge.js +109 -0
  45. package/monitor/DialNeedle.js +36 -0
  46. package/monitor/Format.js +74 -0
  47. package/monitor/centerElement.js +14 -0
  48. package/monitor/compareElements.js +95 -0
  49. package/monitor/defs.js +23 -0
  50. package/monitor/extensions.js +906 -0
  51. package/monitor/functions.js +36 -0
  52. package/monitor/json2xml.js +103 -0
  53. package/monitor/monitorSystem.html +199 -0
  54. package/monitor/monitorSystem.js +322 -0
  55. package/monitor/svgHTML.js +179 -0
  56. package/monitor/svgObjects.js +64 -0
  57. package/package.json +20 -6
  58. package/test/00-objectExtensions.js +94 -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 +2820 -2003
  67. package/test/data/float32vector10.npy +0 -0
  68. package/test/data/flow.json +2830 -2033
  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/dataAnalysisExtensions.js +471 -0
  73. package/test/dataAnalysisPCA.js +54 -0
  74. package/test/dataAnalysisSVD.js +31 -0
  75. package/test/euclideanDistance.js +2 -2
  76. package/test/transformConfluence.js +1 -1
  77. package/test/transformNumPy.js +132 -0
  78. package/testing/test.html +1 -1
  79. package/testing/test.js +78 -53
  80. package/transform/NumPy.js +303 -0
  81. package/transform/transform.html +12 -0
  82. package/transform/transform.js +34 -2
@@ -7,10 +7,11 @@
7
7
  name: {value:"",required:false},
8
8
  action: {value:"avg",required:true},
9
9
  columns:{value:"",required:false},
10
+ lag: {value:1,required:true},
10
11
  outputs: {value:(["realtime","realtimePredict"].includes(this.action)?3:2),required:true},
11
12
  outliersBase: {value:"avg",required:false},
12
13
  outliersStdDevs: {value:"3",required:false},
13
- term: {value:"10",required:false},
14
+ term: {value:10,required:false},
14
15
  keyProperty: {value:"msg.topic",required:false},
15
16
  dataProperty: {value:"msg.payload",required:false},
16
17
  dataProperties: {value:["msg.payload[0]","msg.payload[1]"],required:false}
@@ -27,6 +28,7 @@
27
28
  },
28
29
  oneditprepare: function() {
29
30
  const node=this;
31
+ node.lag??=1
30
32
  $("#node-input-keyProperty").change(function() {
31
33
  if( [null,""].includes(node.keyProperty) ) {
32
34
  $(this).val("msg.topic");
@@ -45,49 +47,62 @@
45
47
  }
46
48
  });
47
49
  $("#node-input-action").change(function() {
48
- if(["distances","distancesMax","distancesMin"].includes( $(this).val() )) {
50
+ if(["differenceSeasonal","differenceSeasonalSecondOrder","realtime","realtimePredict"].includes( $(this).val() )) {
51
+ $(".form-row-http-in-lag").show();
52
+ } else {
53
+ $(".form-row-http-in-lag").hide();
54
+ }
55
+ if(["distances","distancesMax","distancesMin"].includes( $(this).val() )) {
49
56
  $(".form-row-http-in-columns").show();
50
- } else {
57
+ } else {
51
58
  $(".form-row-http-in-columns").hide();
52
- }
59
+ }
53
60
  if(["movingAvgSimple","movingAvgWeighted","movingAvgExponential","realtime","realtimePredict"].includes( $(this).val() )) {
54
61
  $(".form-row-http-in-term").show();
55
- } else {
62
+ } else {
56
63
  $(".form-row-http-in-term").hide();
57
- }
58
- if(["movingAvgExponential"].includes( $(this).val() )) {
64
+ }
65
+ if(["movingAvgExponential"].includes( $(this).val() )) {
59
66
  $("#node-input-term").attr({min:0,max:1,step:0.1});
60
67
  if(node.term<0 || node.term>1) $("#node-input-term").val(0.5);
61
68
  $("#node-input-term").change(function() {
62
69
  if(node.term<0) $(this).val(0);
63
70
  if(node.term>1) $(this).val(1);
64
71
  });
65
- } else {
72
+ } else {
73
+ $("#node-input-lag").attr({min:1,max:1000,step:1});
74
+ $("#node-input-lag").change(function() {
75
+ const v=$(this).val();
76
+ if(v<1) $(this).val(1);
77
+ if(v>1000) $(this).val(1000);
78
+ });
66
79
  $("#node-input-term").attr({min:1,max:100,step:1});
67
80
  $("#node-input-term").change(function() {
68
- if(node.term<1) $(this).val(1);
69
- if(node.term>100) $(this).val(100);
81
+ const v=$(this).val()
82
+ if(v<1) $(this).val(1);
83
+ if(v>100) $(this).val(100);
70
84
  });
71
- }
72
- if(["realtime","realtimePredict"].includes( $(this).val() )) {
85
+ }
86
+ if(["realtime","realtimePredict"].includes( $(this).val() )) {
73
87
  node.outputs=3;
74
88
  $(".form-row-http-in-keyProperty").show();
75
89
  $(".form-row-http-in-outliersStdDevs").show();
76
90
  $(".form-row-http-in-outliersBase").show();
77
91
  $("#node-input-outliersStdDevs").change();
78
- } else {
92
+ } else {
79
93
  node.outputs=2;
80
94
  $(".form-row-http-in-keyProperty").hide();
81
95
  $(".form-row-http-in-outliersStdDevs").hide();
82
96
  $(".form-row-http-in-outliersBase").hide();
83
- }
84
- if(["pearsonR","covariance","corelationship"].includes( $(this).val() )) {
97
+ }
98
+ if(["pearsonR","covariance","corelationship"].includes( $(this).val() )) {
85
99
  $(".node-input-dataProperties-container-row").show();
86
100
  $(".form-row-http-in-dataProperty").hide();
87
- } else {
101
+ } else {
88
102
  $(".node-input-dataProperties-container-row").hide();
89
103
  $(".form-row-http-in-dataProperty").show();
90
- }
104
+ }
105
+ $("#node-input-lag").change();
91
106
  $("#node-input-term").change();
92
107
  });
93
108
 
@@ -148,6 +163,10 @@
148
163
  <option value="corelationship">Corelationship</option>
149
164
  <option value="deltas">Deltas</option>
150
165
  <option value="deltaNormalised">Deltas Normalised</option>
166
+ <option value="difference">Difference</option>
167
+ <option value="differenceSeasonal">Difference Seasonal</option>
168
+ <option value="differenceSeasonalSecondOrder">Difference Seasonal Second Order</option>
169
+ <option value="differenceSecondOrder">Difference Second Order</option>
151
170
  <option value="distances">Euclidean Distances</option>
152
171
  <option value="distancesMax">Euclidean Distances Max</option>
153
172
  <option value="distancesMin">Euclidean Distances Min</option>
@@ -162,6 +181,7 @@
162
181
  <option value="movingAvgExponential">Moving Average Exponential (EMA/EWMA)</option>
163
182
  <option value="normalize">Normalise</option>
164
183
  <option value="pearsonR">Pearson Product Moment Correlation (PPMC)</option>
184
+ <option value="randomise">Randomise</option>
165
185
  <option value="range">Range</option>
166
186
  <option value="realtime">RealTime Metrics</option>
167
187
  <option value="realtimePredict">RealTime Metrics + predicts</option>
@@ -179,6 +199,11 @@
179
199
  <label for="node-input-columns"><i class="icon-bookmark"></i> Columns</label>
180
200
  <input type="text" id="node-input-columns" placeholder="columns">
181
201
  </div>
202
+
203
+ <div class="form-row form-row-http-in-lag hide">
204
+ <label for="node-input-lag"><i class="icon-bookmark"></i> Lag</label>
205
+ <input type="number" id="node-input-lag" placeholder="lag" min="1" max="10000" step="1">
206
+ </div>
182
207
 
183
208
  <div class="form-row form-row-http-in-term hide">
184
209
  <label for="node-input-term"><i class="icon-bookmark"></i> Term</label>
@@ -231,12 +256,18 @@ Data is not persisted so metrics start from zero sample set on node recycle.
231
256
  <p>
232
257
  If real-time stats then a message can send directive instruction in topic:
233
258
  <dl>
234
- <dt>"@predict <key>"<\dt><dd></dd>Send send predictions to second port for selected key.
235
- <dt>"@stats"<\dt><dd></dd>send all stored metrics and retained datapoints to second port.
236
- <dt>"@stats reset"<\dt><dd>Reset all stats and "@stats reset <key>" will reset a particular data point.</dd>
237
- <dt>"@stats set"<\dt><dd>Set stats with ith msg.payload and "@stats set <a data point>" will set a particular data point with msg.payload.</dd>
259
+ <dt>"@predict <key>"</dt><dd></dd>Send send predictions to second port for selected key.
260
+ <dt>"@stats"</dt><dd></dd>send all stored metrics and retained datapoints to second port.
261
+ <dt>"@stats reset"</dt><dd>Reset all stats and "@stats reset <key>" will reset a particular data point.</dd>
262
+ <dt>"@stats set"</dt><dd>Set stats with ith msg.payload and "@stats set &lt;a data point&gt;" will set a particular data point with msg.payload.</dd>
238
263
  </dl>
239
264
  </p>
265
+ <dl>
266
+ <dt>Lag</dt><dd>If greater that 1 generates seasonal difference with degree lag</dd>
267
+ <dt>Term</dt><dd>The depth of moving Average</dd>
268
+ </dl>
269
+ <p>
270
+ </p>
240
271
  <p>
241
272
  Outliers are not within:
242
273
  <ul>
@@ -2,6 +2,11 @@ const logger = new (require("node-red-contrib-logger"))("Data Analysis");
2
2
  logger.sendInfo("Copyright 2020 Jaroslav Peter Prib");
3
3
 
4
4
  require("./arrayLast");
5
+ require("./arrayDifference")
6
+ require("./arrayDifferenceSeasonal")
7
+ require("./arrayDifferenceSeasonalSecondOrder")
8
+ require("./arrayDifferenceSecondOrder")
9
+ require("./arrayRandom")
5
10
  const ed=require("./euclideanDistance.js");
6
11
  require("./forNestedEach");
7
12
 
@@ -64,10 +69,10 @@ EMA.prototype.sample=function(value) {
64
69
  return this;
65
70
  }
66
71
 
67
- function setDataPoint(value,term,node,dp) {
68
- if(logger.active) logger.send({label:"setDataPoint",value:value,term,dp});
69
- if(!dp.values) {
70
- Object.assign(dp,{
72
+ function setDataPoint(value,term,node,dataPoint) {
73
+ if(logger.active) logger.send({label:"setDataPoint",value:value,term,dataPoint});
74
+ if(!dataPoint.values) {
75
+ Object.assign(dataPoint,{
71
76
  values:[],
72
77
  avg:0,
73
78
  count:0,
@@ -78,43 +83,44 @@ function setDataPoint(value,term,node,dp) {
78
83
  sum:0,
79
84
  sumSquared:0,
80
85
  sumCubed:0,
81
- term:term,
86
+ term:term??node.term,
82
87
  weightedMovingSum:0,
83
88
  exponentialWeightedMoving:[new EMA(0.25),new EMA(0.5),new EMA(0.75)]
84
89
  });
85
- }
86
- ;
87
- const count=++dp.count,values=dp.values;
90
+ };
91
+ const count=++dataPoint.count,values=dataPoint.values;
88
92
  values.push(value);
89
- dp.isMaxSize=(values.length>dp.term);
90
- dp.removedValue=(dp.isMaxSize?values.shift():0);
91
- const removedValue=dp.removedValue;
92
- dp.max=Math.max(dp.max||value,value);
93
- dp.min=Math.min(dp.min||value,value);
94
- dp.range=dp.max-dp.min;
95
- dp.sum+=value;
96
- dp.sumSquared+=Math.pow(value,2);
97
- dp.sumCubed+=Math.pow(value,3);
98
- dp.movingSum+=value-removedValue;
99
- dp.movingSumSquared+=Math.pow(value,2)-Math.pow(removedValue,2);
100
- dp.movingSumCubed+=Math.pow(value,3)-Math.pow(removedValue,3);
101
- dp.avg=dp.sum/count;
102
- const avg=dp.avg;
103
- dp.normalised=dp.range ? (value-avg)/dp.range : 0;
104
- dp.movingAvg=dp.movingSum/values.length;
105
- dp.variance=dp.sumSquared/count - Math.pow(avg,2);
106
- dp.stdDev=Math.sqrt(dp.variance);
107
- dp.movingVariance=dp.movingSumSquared/values.length - Math.pow(dp.movingAvg,2);
108
- dp.movingStdDev=Math.sqrt(dp.movingVariance);
109
- dp.median=functions.median(values);
110
- dp.standardized=( (value-avg)/dp.stdDev )||0;
111
- dp.movingStandardized=( (value-dp.movingAvg)/dp.movingStdDev )||0;
112
- dp.skewness=(dp.sumCubed-3*avg*dp.variance-Math.pow(avg,3))/dp.variance*dp.stdDev;
113
- dp.movingSkewness=(dp.movingSumCubed-3*dp.movingAvg*dp.movingVariance-Math.pow(dp.movingAvg,3))/dp.movingVariance*dp.stdDev;
114
- dp.outlier=node.outliersFunction(node,dp,value);
115
- dp.weightedMovingSum+=count*value;
116
- dp.weightedMovingAvg=(dp.weightedMovingAvg*2/count)/(count+1);
117
- dp.exponentialWeightedMoving.forEach(c=>c.sample(value));
93
+ const movingTerm=Math.min(values.length,dataPoint.term)
94
+ dataPoint.isMaxSize=(values.length>dataPoint.maxSize);
95
+ dataPoint.removedMovingValue=(dataPoint.isMaxSize?values[values.length-dataPoint.term]:0);
96
+ dataPoint.removedValue=(dataPoint.isMaxSize?values.shift():0);
97
+ const removedMovingValue=dataPoint.removedMovingValue;
98
+ dataPoint.max=Math.max(dataPoint.max||value,value);
99
+ dataPoint.min=Math.min(dataPoint.min||value,value);
100
+ dataPoint.range=dataPoint.max-dataPoint.min;
101
+ dataPoint.sum+=value;
102
+ dataPoint.sumSquared+=Math.pow(value,2);
103
+ dataPoint.sumCubed+=Math.pow(value,3);
104
+ dataPoint.movingSum+=value-removedMovingValue;
105
+ dataPoint.movingSumSquared+=Math.pow(value,2)-Math.pow(removedMovingValue,2);
106
+ dataPoint.movingSumCubed+=Math.pow(value,3)-Math.pow(removedMovingValue,3);
107
+ dataPoint.avg=dataPoint.sum/count;
108
+ const avg=dataPoint.avg;
109
+ dataPoint.normalised=dataPoint.range ? (value-avg)/dataPoint.range : 0;
110
+ dataPoint.movingAvg=dataPoint.movingSum/movingTerm;
111
+ dataPoint.variance=dataPoint.sumSquared/count - Math.pow(avg,2);
112
+ dataPoint.stdDev=Math.sqrt(dataPoint.variance);
113
+ dataPoint.movingVariance=dataPoint.movingSumSquared/movingTerm - Math.pow(dataPoint.movingAvg,2);
114
+ dataPoint.movingStdDev=Math.sqrt(dataPoint.movingVariance);
115
+ dataPoint.median=functions.median(values);
116
+ dataPoint.standardized=( (value-avg)/dataPoint.stdDev )||0;
117
+ dataPoint.movingStandardized=( (value-dataPoint.movingAvg)/dataPoint.movingStdDev )||0;
118
+ dataPoint.skewness=(dataPoint.sumCubed-3*avg*dataPoint.variance-Math.pow(avg,3))/dataPoint.variance*dataPoint.stdDev;
119
+ dataPoint.movingSkewness=(dataPoint.movingSumCubed-3*dataPoint.movingAvg*dataPoint.movingVariance-Math.pow(dataPoint.movingAvg,3))/dataPoint.movingVariance*dataPoint.stdDev;
120
+ dataPoint.outlier=node.outliersFunction(node,dataPoint,value);
121
+ dataPoint.weightedMovingSum+=count*value;
122
+ dataPoint.weightedMovingAvg=(dataPoint.weightedMovingAvg*2/count)/(count+1);
123
+ dataPoint.exponentialWeightedMoving.forEach(c=>c.sample(value));
118
124
  }
119
125
  function getColumns(node) {
120
126
  if(node.columns) {
@@ -157,6 +163,10 @@ functions={
157
163
  },
158
164
  distancesMin: (d,term,node)=>ed.minDistances(d,getColumns(node)),
159
165
  distancesMax: (d,term,node)=>ed.maxDistances(d,getColumns(node)),
166
+ difference: (d)=>d.difference(),
167
+ differenceSeasonal: (d,term,node)=>d.differenceSeasonal(node.lag),
168
+ differenceSeasonalSecondOrder: (d,term,node)=>d.differenceSeasonalSecondOrder(node.lag),
169
+ differenceSecondOrder: (d)=>d.differenceSecondOrder(),
160
170
  max: (d)=> Math.max(...d),
161
171
  median:(d)=>{
162
172
  const i=Math.floor(d.length/2);
@@ -214,9 +224,9 @@ functions={
214
224
  }
215
225
  }
216
226
  node.samples++;
217
- for(let v,dp,i=0; i<node.dataProperties.length; i++) {
218
- v=d[i];
219
- dp=node.dataPoints[i];
227
+ for(let i=0; i<node.dataProperties.length; i++) {
228
+ const v=d[i];
229
+ const dp=node.dataPoints[i];
220
230
  dp.sum+=v;
221
231
  dp.sumSquared+=v*v;
222
232
  for(let j=i+1; j<node.dataProperties.length; j++) {
@@ -271,10 +281,23 @@ functions={
271
281
  }
272
282
  setDataPoint(d.value,term,node,dp);
273
283
  if(dp.delta) {
274
- setDataPoint(d.value-dp.values[dp.values.length-2],term,node,dp.delta);
284
+ if(dp.values.length>1)
285
+ setDataPoint(d.value-dp.values[dp.values.length-2],term,node,dp.delta);
275
286
  } else {
276
287
  dp.delta={};
277
288
  }
289
+ if(node.lag>1) {
290
+ const vectorSize=dp.values.length
291
+ if(dp.lag) {
292
+ if(node.lag<=vectorSize){
293
+ setDataPoint(d.value-dp.values[vectorSize-node.lag],term,node,dp.lag)
294
+ const values=dp.lag.values
295
+ if(values.length>1) setDataPoint(values[values.length-1]-values[values.length-2],term,node,dp.lag.delta)
296
+ }
297
+ } else {
298
+ dp.lag={delta:{}}
299
+ }
300
+ }
278
301
  return dp;
279
302
  },
280
303
  sampleVariance:(d)=>{
@@ -301,11 +324,15 @@ module.exports = function (RED) {
301
324
  function dataAnalysisNode(n) {
302
325
  RED.nodes.createNode(this, n);
303
326
  const node=Object.assign(this,
304
- {outliersStdDevs:3,crossNormalisedDeltas:crossNormalisedDeltas.bind(this)},
327
+ {outliersStdDevs:3,crossNormalisedDeltas:crossNormalisedDeltas.bind(this),lag:1,term:3},
305
328
  n,
306
329
  {maxErrorDisplay:10,dataPoint:{}}
307
330
  );
308
331
  try{
332
+ node.lag=Number(node.lag)
333
+ if(Number(node.term)==NaN)throw Error("term not a number, value:"+JSON.stringify(node.term))
334
+ node.term=Number(node.term)
335
+ node.maxSize=Math.max(node.term,node.lag)
309
336
  if(functions.hasOwnProperty(node.action)) {
310
337
  node.actionfunction=functions[node.action];
311
338
  } else {
@@ -313,7 +340,7 @@ module.exports = function (RED) {
313
340
  }
314
341
  switch (node.action) {
315
342
  case "realtime":
316
- node.outliersStdDevs=Number.parseInt(node.outliersStdDevs,10)||3;
343
+ node.outliersStdDevs=Number.parseInt(node.outliersStdDevs,10)||3;
317
344
  if(![1,2,3].includes(node.outliersStdDevs)) throw Error("outlier std deviation "+node.outliersStdDevs+" not 1,2 or 3");
318
345
  const outliersFunction=(node.outliersBase||"avg")=="median";
319
346
  node.log("realtime outliersBase set avg "+outliersFunction);
@@ -340,6 +367,7 @@ module.exports = function (RED) {
340
367
  node.getData=eval(node.getDatafunction);
341
368
  node.status({fill:"green",shape:"ring",text:"Ready"});
342
369
  } catch(ex) {
370
+ if(logger.active) logger.send({label:"initialise error",action:node.action,message:ex.message,stack:ex.stack});
343
371
  logger.send({label:"initialise error",node:n});
344
372
  node.error(ex);
345
373
  node.status({fill:"red",shape:"ring",text:"Invalid setup "+ex.message});
@@ -379,6 +407,7 @@ module.exports = function (RED) {
379
407
  throw Error("unknown");
380
408
  }
381
409
  } catch(ex) {
410
+ if(logger.active) logger.send({label:"error input",action:node.action,message:ex.message,stack:ex.stack});
382
411
  node.error(msg.topic+" failed "+ex.message);
383
412
  }
384
413
  return;
@@ -395,10 +424,10 @@ module.exports = function (RED) {
395
424
  break;
396
425
  }
397
426
  } catch(ex) {
398
- if(logger.active) logger.send({label:"error input",action:node.action,message:ex.message,stack:ex.stack});
399
427
  msg.error=ex.message;
400
428
  if(node.maxErrorDisplay) {
401
429
  --node.maxErrorDisplay;
430
+ logger.send({label:"error input",action:node.action,message:ex.message,stack:ex.stack});
402
431
  if(node.action=="realtime") {
403
432
  node.error(node.action+" error: "+ex.message);
404
433
  } else {
@@ -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;