node-red-contrib-prib-functions 0.16.0 → 0.18.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.
@@ -0,0 +1,614 @@
1
+ const logger = new (require("node-red-contrib-logger"))("Matrix");
2
+ logger.sendInfo("Copyright 2022 Jaroslav Peter Prib");
3
+
4
+ const zeroFloat32Value=1e-6;
5
+ function Matrix(rows,columns,fill) {
6
+ if(rows instanceof Array) {
7
+ this.rows=rows.length;
8
+ if(this.rows==0) throw Error("expected rows")
9
+ const row=rows[0];
10
+ if(!row instanceof Array) throw Error("expected row to be array of columns")
11
+ this.columns=row.length;
12
+ if(this.columns==0) throw Error("expected Columns")
13
+ this.createVector().fillArray(rows);
14
+ return this;
15
+ }
16
+ if(rows instanceof Object) {
17
+ Object.assign(this,rows);
18
+ } else {
19
+ this.rows=rows;
20
+ this.columns=columns;
21
+ }
22
+ this.createVector();
23
+ return this;
24
+ }
25
+ Matrix.prototype.add=function(matrix){
26
+ this.forEachCellPairSet(matrix,(cellA,cellB)=>cellA+cellB)
27
+ return this;
28
+ }
29
+ Matrix.prototype.addCell=function(row,column,value){
30
+ this.vector[this.getIndex(row,column)]+=value;
31
+ return this;
32
+ }
33
+ Matrix.prototype.addRow=function(vector){
34
+ if(this.size==this.sizeMax){
35
+ this.vector.copyWithin(0,this.columns,this.sizeMax);
36
+ this.rows--;
37
+ this.size-=this.columns;
38
+ }
39
+ this.vector.set(vector, this.rows*this.columns);
40
+ this.rows++;
41
+ this.size+=this.columns;
42
+ return this;
43
+ }
44
+ Matrix.prototype.addRow2Row=function(rowA,rowB,factor=1,startColumn=0,endColumn=this.columns-1){
45
+ const diff=(rowA-rowB)*this.columns;
46
+ this.forRowCells(rowB,(value,column,offset,vector)=>vector[offset]+=vector[offset+diff]*factor,startColumn,endColumn);
47
+ return this;
48
+ }
49
+ Matrix.prototype.backwardSubstitution=function(){
50
+ const vector=new Float32Array(this.rows);
51
+ for(let row=this.rows-1; row>=0; row--) {
52
+ vector[row] = this.get(row,this.rows);
53
+ for(let column=row+1; column<this.rows; column++) {
54
+ vector[row] -= this.get(row,column)*vector[column];
55
+ }
56
+ vector[row] /= this.get(row,row);
57
+ }
58
+ return vector;
59
+ }
60
+ Matrix.prototype.clone=function(){
61
+ const matrix= new Matrix({rows:this.rows,columns:this.columns,size:this.size,sizeMax:this.sizeMax})
62
+ matrix.vector.set(this.vector,0);
63
+ return matrix
64
+ }
65
+ Matrix.prototype.consoleLog=function(label){
66
+ console.log({label:label,rows:this.rows,columns:this.columns,size:this.size,sizeMax:this.sizeMax})
67
+ return this;
68
+ }
69
+ Matrix.prototype.createLike=function(matrix){
70
+ return new Matrix({rows:this.rows,columns:this.columns,size:this.size,sizeMax:this.sizeMax})
71
+ }
72
+ Matrix.prototype.createForEachCellPairSet=function(matrix,call){
73
+ const result=this.createLike();
74
+ if(matrix instanceof Matrix){
75
+ if(this.rows!=matrix.rows) throw Error("number of rows different");
76
+ if(this.columns!=matrix.columns) throw Error("number of columns different");
77
+ for(let offset=0;offset<this.size;offset++)
78
+ result.vector[offset]=call.apply(this,[this.vector[offset],matrix.vector[offset]]);
79
+ return result;
80
+ }
81
+ if(this.rows!=matrix.length) throw Error("number of rows different");
82
+ if(this.columns!=matrix[0].length) throw Error("number of columns different");
83
+ for(let offset=0,row=0;row<this.rows;row++) {
84
+ for(let column=0;column<this.columns;column++) {
85
+ result.vector[offset]=call.apply(this,[this.vector[offset],matrix[row][column]]);
86
+ offset++
87
+ }
88
+ }
89
+ return result;
90
+ }
91
+ Matrix.prototype.createVector=function(){
92
+ if(this.size==null) {
93
+ if(this.rows==null){
94
+ if(this.rowsMax==null) throw Error("rows or rowsMax not specified")
95
+ this.rows=0;
96
+ this.sizeMax=this.rowsMax*this.columns;
97
+ }
98
+ if(this.columns==null) throw Error("columns not specified")
99
+ this.size=this.rows*this.columns
100
+ if(this.sizeMax==null) this.sizeMax=this.size
101
+ } else {
102
+ if(this.columns==null) throw Error("columns not specified")
103
+ if(this.rows==null){
104
+ this.rows=0;
105
+ }
106
+ }
107
+ this.vector=new Float32Array(this.sizeMax);
108
+ return this;
109
+ }
110
+ Matrix.prototype.divideCell=function(row,column,value){
111
+ this.vector[this.getIndex(row,column)]/=value;
112
+ return this;
113
+ }
114
+ Matrix.prototype.divideRow=function(row,factor,startColumn=0,endColumn=this.columns-1){
115
+ this.determinant/=factor;
116
+ this.forRowCells(row,(value,column,offset,vector)=>vector[offset]/=factor,startColumn,endColumn);
117
+ return this;
118
+ }
119
+ Matrix.prototype.equalsNearly=function(matrix,precision=6){
120
+ const thisObject=this;
121
+ if(matrix instanceof Matrix){
122
+ if(this.rows!=matrix.rows) throw Error("rows counts not equal actual: "+this.rows+" expected: "+matrix.rows)
123
+ if(this.columns!=matrix.columns) throw Error("columns counts not equal actual: "+this.columns+" expected: "+matrix.columns)
124
+ this.forEachCell((value,row,column,vector,offset)=>{
125
+ try{
126
+ thisObject.equalsNearlyValues(value,matrix.vector[offset],precision)
127
+ } catch(ex) {
128
+ throw Error("row: "+row+" column: "+column+", cell values "+ex.message)
129
+ }
130
+ });
131
+ } else {
132
+ if(this.rows!=matrix.length) throw Error("rows counts not equal actual: "+this.rows+" expected: "+matrix.length)
133
+ if(this.columns!=matrix[0].length) throw Error("columns counts not equal actual: "+this.columns+" expected: "+matrix[0].length)
134
+ this.forEachCell((value,row,column)=>{
135
+ try{
136
+ thisObject.equalsNearlyValues(value,matrix[row][column],precision)
137
+ } catch(ex) {
138
+ throw Error("row: "+row+" column: "+column+", cell values "+ex.message)
139
+ }
140
+ });
141
+ }
142
+ return this;
143
+ }
144
+ Matrix.prototype.equalsNearlyValues=function(x,y,precision=6){
145
+ if(x==0){
146
+ if(y.toFixed(precision)==0) return this;
147
+ } else {
148
+ if((y/x).toFixed(precision)==1) return this;
149
+ }
150
+ throw Error(x+" != "+y);
151
+ return this;
152
+ }
153
+ Matrix.prototype.equalsNearlyVector=function(vector,precision=6,baseVector=this.vector){
154
+ baseVector.forEach((v,i,a)=>{
155
+ try{
156
+ this.equalsNearlyValues(v,vector[i],precision)
157
+ } catch(ex) {
158
+ throw Error('not equal, index '+i+' left: '+v+' right: '+vector[i]);
159
+ }
160
+ })
161
+ return this;
162
+ }
163
+ Matrix.prototype.fill=function(value, start, end){
164
+ this.vector.fill(value, start, end);
165
+ return this;
166
+ }
167
+ Matrix.prototype.fillArray=function(a){
168
+ const matrix=this;
169
+ a.forEach((columns)=>matrix.addRow(columns))
170
+ return this;
171
+ }
172
+ Matrix.prototype.findColumnRow=function(column,call,startRow=0,endRow=this.rows-1){
173
+ let offset=startRow*this.columns+column;
174
+ for(let row=startRow;row<=this.rows;row++){
175
+ if(call.apply(this,[this.vector[offset],row,offset,this.vector])) {
176
+ return row;
177
+ }
178
+ offset+=this.columns;
179
+ }
180
+ return -1;
181
+ }
182
+ Matrix.prototype.findRowColumn=function(row,call,startColumn=0,endColumn=this.columns-1){
183
+ let offset=row*this.columns+startColumn;
184
+ for(let column=startColumn;column<=endColumn;column++){
185
+ if(call.apply(this,[this.vector[offset],column,offset,this.vector]))
186
+ return column;
187
+ offset++;
188
+ }
189
+ return -1;
190
+ }
191
+ Matrix.prototype.forColumnCells=function(column,call,startRow=0,endRow=this.rows-1){
192
+ let offset=startRow*this.columns+column;
193
+ for(let row=startRow;row<=endRow;row++){
194
+ call.apply(this,[this.vector[offset],row,offset,this.vector]);
195
+ offset+=this.columns;
196
+ }
197
+ return this;
198
+ }
199
+ Matrix.prototype.forEachCell=function(call){
200
+ for(let offset=0,row=0;row<this.rows;row++) {
201
+ for(let column=0;column<this.columns;column++) {
202
+ call.apply(this,[this.vector[offset],row,column,this.vector,offset,this]);
203
+ offset++
204
+ }
205
+ }
206
+ return this;
207
+ }
208
+ Matrix.prototype.forEachCellPairSet=function(matrix,call){
209
+ if(matrix instanceof Matrix){
210
+ if(this.rows!=matrix.rows) throw Error("number of rows different");
211
+ if(this.columns!=matrix.columns) throw Error("number of columns different");
212
+ for(let offset=0;offset<this.size;offset++)
213
+ this.vector[offset]=call.apply(this,[this.vector[offset],matrix.vector[offset]]);
214
+ return this;
215
+ }
216
+ if(this.rows!=matrix.length) throw Error("number of rows different");
217
+ if(this.columns!=matrix[0].length) throw Error("number of columns different");
218
+ for(let offset=0,row=0;row<this.rows;row++) {
219
+ for(let column=0;column<this.columns;column++) {
220
+ this.vector[offset]=call.apply(this,[this.vector[offset],matrix[row][column]]);
221
+ offset++
222
+ }
223
+ }
224
+ return this;
225
+ }
226
+ Matrix.prototype.forEachRow=function(call){
227
+ for(let row=0;row<this.rows;row++) {
228
+ const rowVector=this.getRow(row);
229
+ call.apply(this,[rowVector,row,this])
230
+ }
231
+ return this;
232
+ }
233
+ Matrix.prototype.forRowCells=function(row,call,startColumn=0,endColumn=this.columns-1){
234
+ let offset=row*this.columns+startColumn;
235
+ for(let column=startColumn;column<=endColumn;column++){
236
+ call.apply(this,[this.vector[offset],column,offset,this.vector]);
237
+ offset++;
238
+ }
239
+ return this;
240
+ }
241
+ Matrix.prototype.forwardElimination=function(){
242
+ let maxValue,maxRow;
243
+ for(let pivotRowColumn=0; pivotRowColumn<this.rows; pivotRowColumn++) {
244
+ maxRow=pivotRowColumn; // Initialize maximum value and index for pivot
245
+ maxValue=Math.abs(this.get(maxRow,pivotRowColumn));
246
+ for(let row=pivotRowColumn+1; row<this.rows; row++){
247
+ const value=Math.abs(this.get(row,pivotRowColumn))
248
+ if(value>maxValue) {
249
+ maxValue=value;
250
+ maxRow=row;
251
+ }
252
+ }
253
+ // if a principal diagonal element is zero then matrix is singular + division-by-zero later
254
+ if(this.get(pivotRowColumn,maxRow)==0) {
255
+ throw Error("Singular matrix, "+(this.get(pivotRowColumn,this.columns)==0?"may have infinitely many solutions":"inconsistent system"))
256
+ }
257
+ if(maxRow!=pivotRowColumn) this.swapRows(pivotRowColumn, maxRow);
258
+ pivotValue=this.get(pivotRowColumn,pivotRowColumn);
259
+ for(let row=pivotRowColumn+1; row<this.rows; row++){
260
+ const factor=this.get(row,pivotRowColumn)/pivotValue;
261
+ for(let column=pivotRowColumn+1; column<this.columns; column++){
262
+ this.subtractCell(row,column,this.get(pivotRowColumn,column)*factor);
263
+ }
264
+ this.set(row,pivotRowColumn,0);
265
+ }
266
+ }
267
+ return this;
268
+ }
269
+ Matrix.prototype.gaussianElimination=function(){
270
+ return this.forwardElimination().backwardSubstitution();
271
+ }
272
+ Matrix.prototype.get=function(row, column){
273
+ return this.vector[row*this.columns+column];
274
+ }
275
+ Matrix.prototype.getAdjoint=function(){
276
+ if(this.columns==1) return new Matrix([[1]]);
277
+ const adjoint=this.createLike();
278
+ for(let offset=0,row=0;row<adjoint.rows;row++) {
279
+ for(let column=0;column<adjoint.columns;column++) {
280
+ const temp=this.getCofactor(column,row); // get reverse
281
+ adjoint.vector[offset]=((row+column)%2==0)?temp.getDeterminant():-temp.getDeterminant();
282
+ offset++
283
+ }
284
+ }
285
+ return adjoint;
286
+ }
287
+ Matrix.prototype.getCofactor=function(cellRow,cellColumn){
288
+ const matrixSize=this.rows-1;
289
+ const matrix=new Matrix(matrixSize,matrixSize)
290
+ const startLength=cellColumn;
291
+ const endLength=matrixSize-cellColumn;
292
+ const columnOffsetPart2=cellColumn+1;
293
+ let thisRowOffset=0;matrixRowOffset=0;
294
+ for(let row=0;row<this.rows;row++) {
295
+ if(row!==cellRow){
296
+ const vectorStart=this.vector.slice(thisRowOffset,thisRowOffset+startLength);
297
+ const thisRowOffsetPart2=thisRowOffset+columnOffsetPart2;
298
+ const vectorEnd=this.vector.slice(thisRowOffsetPart2,thisRowOffsetPart2+endLength);
299
+ matrix.vector.set(vectorStart,matrixRowOffset);
300
+ matrix.vector.set(vectorEnd,matrixRowOffset+cellColumn)
301
+ matrixRowOffset+=matrixSize; //next rows
302
+ }
303
+ thisRowOffset+=this.rows
304
+ }
305
+ return matrix;
306
+ }
307
+ Matrix.prototype.getComplementMinor=function(cellRow, cellColumn){
308
+ const matrix = new Matrix(this.rows-1,this.columns-1);
309
+ for(let row=0,column=0,sourceRow=0; sourceRow<this.rows; sourceRow++) {
310
+ if(sourceRow==cellRow) continue;
311
+ for(let sourceColumn=0; sourceColumn<this.columns; sourceColum++) {
312
+ if(sourceColum==cellColumn) continue; // In the first sourceRow Data ellipsis of column
313
+ matrix.set(row,column,this.get(sourceRow, sourceColumn));
314
+ column++;
315
+ if(column >= matrix.columns ) {
316
+ column=0;
317
+ row++;
318
+ }
319
+ }
320
+ }
321
+ return matrix;
322
+ }
323
+ Matrix.prototype.getDeterminant=function(){
324
+ if(this.determinant) return this.determinant
325
+ this.testIsSquare();
326
+ return this.setDeterminant();
327
+ }
328
+ Matrix.prototype.getDeterminantUsingCofactor=function(){
329
+ this.determinant=0;
330
+ if(this.rows>2) {
331
+ let sign=1;
332
+ for(let column=0; column<this.columns; column++) {
333
+ this.determinant += sign*this.vector[column]*this.getCofactor(0,column).getDeterminantUsingCofactor();
334
+ sign=-sign;
335
+ }
336
+ } else {
337
+ this.determinant=this.vector[0]*this.vector[3]- this.vector[1]*this.vector[2];
338
+ }
339
+ return this.determinant;
340
+ }
341
+ Matrix.prototype.getDeterminantUsingRowEchelonForm=function(){
342
+ if(this.rows==1) return this.vector[0];
343
+ const matrix=this.clone();
344
+ matrix.determinant=parseFloat(1); //force use of float
345
+ matrix.rowEchelonForm();
346
+ this.determinant=1/matrix.determinant;
347
+ return this.determinant;
348
+ }
349
+ Matrix.prototype.getIdentity=function(){
350
+ const identity=this.createLike();
351
+ for(let offset=0;offset<identity.size;offset+=identity.columns+1) identity.vector[offset]=1;
352
+ return identity;
353
+ }
354
+ Matrix.prototype.getIndex=function(row, column){
355
+ return row*this.columns+column;
356
+ }
357
+ Matrix.prototype.getInverse=Matrix.prototype.getInverseGaussJordan;
358
+ Matrix.prototype.getInverseAdjointMethod=function(){
359
+ const determinant=this.getDeterminant();
360
+ if(determinant==0) throw Error("Singular matrix, can't find its inverse");
361
+ const adjoint=this.getAdjoint();
362
+ for(let offset=0;offset<adjoint.size;offset++) {
363
+ adjoint.vector[offset]/=determinant;
364
+ }
365
+ return adjoint;
366
+ }
367
+ Matrix.prototype.getInverseGaussJordan=function(){
368
+ this.testIsSquare();
369
+ const matrix = new Matrix(this.rows, this.columns * 2);
370
+ for (let row=0,offset=this.columns; row<this.rows; ++row) {
371
+ matrix.setRow(this.getRow(row),row);
372
+ matrix.vector[offset+row]=1;
373
+ offset+=matrix.columns
374
+ }
375
+ matrix.reducedRowEchelonForm();
376
+ return matrix.getMatrix(0,this.columns,this.rows,this.columns);
377
+ }
378
+ Matrix.prototype.getMatrix=function(row,column,rows,columns){
379
+ const matrix = new Matrix(rows,columns);
380
+ for(let matrixOffset=0,thisOffset=row*this.columns+column; row<this.rows; ++row,thisOffset+=this.columns,matrixOffset+=rows) {
381
+ matrix.vector.set(this.vector.subarray(thisOffset,thisOffset+columns),matrixOffset)
382
+ }
383
+ return matrix;
384
+ }
385
+ Matrix.prototype.getRow=function(row){
386
+ const start=row*this.columns;
387
+ return this.vector.subarray(start,start+this.columns);
388
+ }
389
+ Matrix.prototype.getZeroed=function(row, column){
390
+ const offset=row*this.columns+column;
391
+ const value=this.vector[offset];
392
+ if(value==0 || Math.abs(value)>zeroFloat32Value) return value;
393
+ this.vector[offset]=0;
394
+ return 0;
395
+ }
396
+ Matrix.prototype.maxAbsColumn=function(column,startRow=0){
397
+ let rowColumnOffset=startRow*this.columns+column;
398
+ let maxValue=Math.abs(this.vector[rowColumnOffset]);
399
+ rowColumnOffset+=this.columns;
400
+ while (rowColumnOffset<this.size) {
401
+ const value=Math.abs(this.vector[rowColumnOffset])
402
+ if(value>maxValue) {
403
+ maxValue=value;
404
+ maxRowColumnOffset=rowColumnOffset;
405
+ };
406
+ rowColumnOffset+=this.columns;
407
+ }
408
+ return {row:(maxRowColumnOffset-column)/this.columns,value:this.vector[maxRowColumnOffset]}
409
+ }
410
+ Matrix.prototype.maxColumn=function(column,startRow=0){
411
+ let rowColumnOffset=startRow*this.columns+column;
412
+ let maxValue=this.vector[rowColumnOffset];
413
+ rowColumnOffset+=this.columns;
414
+ while (rowColumnOffset<this.size) {
415
+ const value=this.vector[rowColumnOffset];
416
+ if(value>maxValue) {
417
+ maxValue=value;
418
+ maxRowColumnOffset=rowColumnOffset;
419
+ };
420
+ rowColumnOffset+=this.columns;
421
+ }
422
+ return {row:(maxRowColumnOffset-column)/this.columns,value:this.vector[maxRowColumnOffset]}
423
+ }
424
+ Matrix.prototype.multiply=function(rightMatrix){
425
+ const leftMatrix=this;
426
+ if(leftMatrix.columns!=rightMatrix.rows) throw Error(leftMatrix.columns+ "columns != "+rightMatrix.rows+" rows of argument");
427
+ const result=new Matrix({rows:leftMatrix.rows,columns:rightMatrix.columns})
428
+ result.forEachCell((cell,row,column)=>{
429
+ const value=leftMatrix.reduceRow(row,
430
+ (value,rowCell,leftRow,leftColumn)=>
431
+ value+rowCell*rightMatrix.get(leftColumn,column)
432
+ );
433
+ result.set(row,column,value);
434
+ })
435
+ return result;
436
+ }
437
+ Matrix.prototype.multiplyRow=function(row,factor){
438
+ this.determinant*=factor;
439
+ this.forRowCells(row,(cell,column,offset,vector)=>vector[offset]*=factor)
440
+ return this;
441
+ }
442
+ Matrix.prototype.reducedRowEchelonForm=function(){
443
+ const lastColumn=this.columns-1;
444
+ for(let pivotColumn=0,pivotRow=0;pivotRow<this.rows;pivotRow++){
445
+ if(this.rows<=pivotRow) throw Error("logic error")
446
+ let row=pivotRow;
447
+ while(this.getZeroed(row,pivotColumn)==0){
448
+ row++
449
+ if(this.rows==row){
450
+ row=pivotRow;
451
+ pivotColumn++
452
+ if(pivotColumn>=this.columns) {
453
+ if(row==this.rows-1) return this;
454
+ throw Error("row all zeroes which is not last row")
455
+ }
456
+ }
457
+ }
458
+ if(row!==pivotRow) this.swapRows(row,pivotRow)
459
+ const factor=this.get(pivotRow,pivotColumn)
460
+ for(let column=pivotColumn;column<this.columns;column++)
461
+ this.divideCell(pivotRow,column,factor)
462
+ if(pivotColumn==lastColumn) break;
463
+ for(let row=0;row<this.rows;row++){
464
+ if(row==pivotRow) continue;
465
+ const factor=-this.getZeroed(row,pivotColumn);
466
+ if(factor==0) continue;
467
+ for(let column=pivotColumn;column<this.columns;column++){
468
+ const value=this.get(pivotRow,column);
469
+ if(value)
470
+ this.addCell(row,column,factor*value)
471
+ }
472
+ }
473
+ if(++pivotColumn>this.columns) break;
474
+ }
475
+ return this;
476
+ }
477
+ Matrix.prototype.rowEchelonForm=function(){
478
+ const columns=this.columns;
479
+ let pivotRow=0,pivotColumn=0,lastRowAdj=this.rows-1;
480
+ nextPivot: while(pivotRow<=lastRowAdj & pivotColumn<columns){
481
+ let pivotValue=this.getZeroed(pivotRow, pivotColumn);
482
+ if(pivotValue==0) {
483
+ const i=this.findRowColumn(pivotRow,value=>Math.abs(value)>zeroFloat32Value,pivotColumn+1,lastRowAdj) //none zeroe?
484
+ if(i==-1){
485
+ if(pivotRow==lastRowAdj) {
486
+ pivotColumn++;
487
+ continue nextPivot;
488
+ }
489
+ this.swapRows(pivotRow,lastRowAdj--);
490
+ if(lastRowAdj<=1) return this;
491
+ continue nextPivot;
492
+ }
493
+ const row=this.findColumnRow(pivotColumn,value=>Math.abs(value)>zeroFloat32Value,pivotRow+1,lastRowAdj);
494
+ if(row==-1) {
495
+ pivotColumn++;
496
+ continue nextPivot;
497
+ }
498
+ this.swapRows(pivotRow,row);
499
+ pivotValue=this.get(pivotRow, pivotColumn);
500
+ }
501
+ this.divideRow(pivotRow,pivotValue,pivotColumn);
502
+ for(let row=pivotRow+1; row<=lastRowAdj; row++) {
503
+ const factor=-this.get(row, pivotColumn);
504
+ this.addRow2Row(pivotRow,row,factor,pivotColumn);
505
+ }
506
+ pivotRow++;
507
+ pivotColumn++;
508
+ }
509
+ return this;
510
+ }
511
+ Matrix.prototype.reduceRow=function(row,call,value=0){
512
+ this.forRowCells(row,(cell,column,offset,vector)=>{
513
+ value=call.apply(this,[value,cell,row,column]);
514
+ });
515
+ return value;
516
+ }
517
+ Matrix.prototype.set=function(row,column,value){
518
+ this.vector[this.getIndex(row,column)]=value;
519
+ return this;
520
+ }
521
+ Matrix.prototype.setDeterminant=function(){
522
+ this.determinant=this.getDeterminantUsingRowEchelonForm();
523
+ return this.determinant;
524
+ }
525
+ Matrix.prototype.setRow=function(vector,row){
526
+ this.vector.set(vector, row*this.columns);
527
+ return this;
528
+ }
529
+ Matrix.prototype.substract=function(matrix){
530
+ this.forEachCellPairSet(matrix,(cellA,cellB)=>cellA-cellB)
531
+ return this;
532
+ }
533
+ Matrix.prototype.subtractCell=function(row,column,value){
534
+ this.vector[this.getIndex(row,column)]-=value;
535
+ return this;
536
+ }
537
+ Matrix.prototype.sumRow=function(row){
538
+ return this.reduceRow(row,(value,cell)=>value+cell);
539
+ }
540
+ Matrix.prototype.swapRows=function(rowA,rowB){
541
+ this.determinant=-this.determinant;
542
+ const startRowA=rowA*this.columns;
543
+ const rowAVector=this.vector.slice(startRowA,startRowA+this.columns);
544
+ const startRowB=rowB*this.columns
545
+ this.vector.copyWithin(startRowA,startRowB,startRowB+this.columns);
546
+ this.vector.set(rowAVector,startRowB);
547
+ return this;
548
+ }
549
+ Matrix.prototype.testIsSquare=function(){
550
+ if(this.rows!=this.columns) throw Error("not square matrix");
551
+ return this;
552
+ }
553
+ Matrix.prototype.toArray=function(precision=6){
554
+ const result=[];
555
+ this.forEachRow((row,index)=>{
556
+ const columns=[];
557
+ row.forEach(value=>columns.push(value))
558
+ result.push(columns)
559
+ })
560
+ return result;
561
+ }
562
+ Matrix.prototype.transpose=function(){
563
+ const matrix=new Matrix({rows:this.columns,columns:this.rows})
564
+ this.forEachCell((cell,row,column)=>matrix.set(column,row,cell))
565
+ return matrix;
566
+ }
567
+
568
+ module.exports=Matrix;
569
+
570
+ /*
571
+ function setDataPoint(value,term,node,dp) {
572
+ Object.assign(dp,{
573
+ avg:0,
574
+ count:0, =rows
575
+ movingSum:0,
576
+ movingSumSquared:0,
577
+ movingSumCubed:0,
578
+ outlier:false,
579
+ sum:0,
580
+ sumSquared:0,
581
+ sumCubed:0,
582
+ term:term,
583
+ weightedMovingSum:0,
584
+ exponentialWeightedMoving:[new EMA(0.25),new EMA(0.5),new EMA(0.75)]
585
+ });
586
+ };
587
+ dp.max=Math.max(dp.max||value,value);
588
+ dp.min=Math.min(dp.min||value,value);
589
+ dp.range=dp.max-dp.min;
590
+ dp.sum+=value;
591
+ dp.sumSquared+=Math.pow(value,2);
592
+ dp.sumCubed+=Math.pow(value,3);
593
+ dp.movingSum+=value-removedValue;
594
+ dp.movingSumSquared+=Math.pow(value,2)-Math.pow(removedValue,2);
595
+ dp.movingSumCubed+=Math.pow(value,3)-Math.pow(removedValue,3);
596
+ // dp.avg=dp.sum/this.rows;
597
+ const avg=dp.avg;
598
+ dp.normalised=dp.range ? (value-avg)/dp.range : 0;
599
+ // dp.movingAvg=dp.movingSum/values.length;
600
+ // dp.variance=dp.sumSquared/count - Math.pow(avg,2);
601
+ // dp.stdDev=Math.sqrt(dp.variance);
602
+ dp.movingVariance=dp.movingSumSquared/values.length - Math.pow(dp.movingAvg,2);
603
+ dp.movingStdDev=Math.sqrt(dp.movingVariance);
604
+ dp.median=functions.median(values);
605
+ dp.standardized=( (value-avg)/dp.stdDev )||0;
606
+ dp.movingStandardized=( (value-dp.movingAvg)/dp.movingStdDev )||0;
607
+ dp.skewness=(dp.sumCubed-3*avg*dp.variance-Math.pow(avg,3))/dp.variance*dp.stdDev;
608
+ dp.movingSkewness=(dp.movingSumCubed-3*dp.movingAvg*dp.movingVariance-Math.pow(dp.movingAvg,3))/dp.movingVariance*dp.stdDev;
609
+ dp.outlier=node.outliersFunction(node,dp,value);
610
+ dp.weightedMovingSum+=count*value;
611
+ dp.weightedMovingAvg=(dp.weightedMovingAvg*2/count)/(count+1);
612
+ dp.exponentialWeightedMoving.forEach(c=>c.sample(value));
613
+ }
614
+ */