ml-matrix 6.5.3 → 6.8.1

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/src/matrix.js CHANGED
@@ -29,6 +29,7 @@ import {
29
29
  checkColumnVector,
30
30
  checkRange,
31
31
  checkIndices,
32
+ checkNonEmpty,
32
33
  } from './util';
33
34
 
34
35
  export class AbstractMatrix {
@@ -219,6 +220,10 @@ export class AbstractMatrix {
219
220
  return this.rows === this.columns;
220
221
  }
221
222
 
223
+ isEmpty() {
224
+ return this.rows === 0 || this.columns === 0;
225
+ }
226
+
222
227
  isSymmetric() {
223
228
  if (this.isSquare()) {
224
229
  for (let i = 0; i < this.rows; i++) {
@@ -556,6 +561,9 @@ export class AbstractMatrix {
556
561
  }
557
562
 
558
563
  max() {
564
+ if (this.isEmpty()) {
565
+ return NaN;
566
+ }
559
567
  let v = this.get(0, 0);
560
568
  for (let i = 0; i < this.rows; i++) {
561
569
  for (let j = 0; j < this.columns; j++) {
@@ -568,6 +576,7 @@ export class AbstractMatrix {
568
576
  }
569
577
 
570
578
  maxIndex() {
579
+ checkNonEmpty(this);
571
580
  let v = this.get(0, 0);
572
581
  let idx = [0, 0];
573
582
  for (let i = 0; i < this.rows; i++) {
@@ -583,6 +592,9 @@ export class AbstractMatrix {
583
592
  }
584
593
 
585
594
  min() {
595
+ if (this.isEmpty()) {
596
+ return NaN;
597
+ }
586
598
  let v = this.get(0, 0);
587
599
  for (let i = 0; i < this.rows; i++) {
588
600
  for (let j = 0; j < this.columns; j++) {
@@ -595,6 +607,7 @@ export class AbstractMatrix {
595
607
  }
596
608
 
597
609
  minIndex() {
610
+ checkNonEmpty(this);
598
611
  let v = this.get(0, 0);
599
612
  let idx = [0, 0];
600
613
  for (let i = 0; i < this.rows; i++) {
@@ -611,6 +624,9 @@ export class AbstractMatrix {
611
624
 
612
625
  maxRow(row) {
613
626
  checkRowIndex(this, row);
627
+ if (this.isEmpty()) {
628
+ return NaN;
629
+ }
614
630
  let v = this.get(row, 0);
615
631
  for (let i = 1; i < this.columns; i++) {
616
632
  if (this.get(row, i) > v) {
@@ -622,6 +638,7 @@ export class AbstractMatrix {
622
638
 
623
639
  maxRowIndex(row) {
624
640
  checkRowIndex(this, row);
641
+ checkNonEmpty(this);
625
642
  let v = this.get(row, 0);
626
643
  let idx = [row, 0];
627
644
  for (let i = 1; i < this.columns; i++) {
@@ -635,6 +652,9 @@ export class AbstractMatrix {
635
652
 
636
653
  minRow(row) {
637
654
  checkRowIndex(this, row);
655
+ if (this.isEmpty()) {
656
+ return NaN;
657
+ }
638
658
  let v = this.get(row, 0);
639
659
  for (let i = 1; i < this.columns; i++) {
640
660
  if (this.get(row, i) < v) {
@@ -646,6 +666,7 @@ export class AbstractMatrix {
646
666
 
647
667
  minRowIndex(row) {
648
668
  checkRowIndex(this, row);
669
+ checkNonEmpty(this);
649
670
  let v = this.get(row, 0);
650
671
  let idx = [row, 0];
651
672
  for (let i = 1; i < this.columns; i++) {
@@ -659,6 +680,9 @@ export class AbstractMatrix {
659
680
 
660
681
  maxColumn(column) {
661
682
  checkColumnIndex(this, column);
683
+ if (this.isEmpty()) {
684
+ return NaN;
685
+ }
662
686
  let v = this.get(0, column);
663
687
  for (let i = 1; i < this.rows; i++) {
664
688
  if (this.get(i, column) > v) {
@@ -670,6 +694,7 @@ export class AbstractMatrix {
670
694
 
671
695
  maxColumnIndex(column) {
672
696
  checkColumnIndex(this, column);
697
+ checkNonEmpty(this);
673
698
  let v = this.get(0, column);
674
699
  let idx = [0, column];
675
700
  for (let i = 1; i < this.rows; i++) {
@@ -683,6 +708,9 @@ export class AbstractMatrix {
683
708
 
684
709
  minColumn(column) {
685
710
  checkColumnIndex(this, column);
711
+ if (this.isEmpty()) {
712
+ return NaN;
713
+ }
686
714
  let v = this.get(0, column);
687
715
  for (let i = 1; i < this.rows; i++) {
688
716
  if (this.get(i, column) < v) {
@@ -694,6 +722,7 @@ export class AbstractMatrix {
694
722
 
695
723
  minColumnIndex(column) {
696
724
  checkColumnIndex(this, column);
725
+ checkNonEmpty(this);
697
726
  let v = this.get(0, column);
698
727
  let idx = [0, column];
699
728
  for (let i = 1; i < this.rows; i++) {
@@ -1012,7 +1041,9 @@ export class AbstractMatrix {
1012
1041
  let newMatrix = new Matrix(this.rows, this.columns);
1013
1042
  for (let i = 0; i < this.rows; i++) {
1014
1043
  const row = this.getRow(i);
1015
- rescale(row, { min, max, output: row });
1044
+ if (row.length > 0) {
1045
+ rescale(row, { min, max, output: row });
1046
+ }
1016
1047
  newMatrix.setRow(i, row);
1017
1048
  }
1018
1049
  return newMatrix;
@@ -1029,11 +1060,13 @@ export class AbstractMatrix {
1029
1060
  let newMatrix = new Matrix(this.rows, this.columns);
1030
1061
  for (let i = 0; i < this.columns; i++) {
1031
1062
  const column = this.getColumn(i);
1032
- rescale(column, {
1033
- min: min,
1034
- max: max,
1035
- output: column,
1036
- });
1063
+ if (column.length) {
1064
+ rescale(column, {
1065
+ min: min,
1066
+ max: max,
1067
+ output: column,
1068
+ });
1069
+ }
1037
1070
  newMatrix.setColumn(i, column);
1038
1071
  }
1039
1072
  return newMatrix;
@@ -1086,6 +1119,18 @@ export class AbstractMatrix {
1086
1119
  return result;
1087
1120
  }
1088
1121
 
1122
+ kroneckerSum(other) {
1123
+ other = Matrix.checkMatrix(other);
1124
+ if (!this.isSquare() || !other.isSquare()) {
1125
+ throw new Error('Kronecker Sum needs two Square Matrices');
1126
+ }
1127
+ let m = this.rows;
1128
+ let n = other.rows;
1129
+ let AxI = this.kroneckerProduct(Matrix.eye(n, n));
1130
+ let IxB = Matrix.eye(m, m).kroneckerProduct(other);
1131
+ return AxI.add(IxB);
1132
+ }
1133
+
1089
1134
  transpose() {
1090
1135
  let result = new Matrix(this.columns, this.rows);
1091
1136
  for (let i = 0; i < this.rows; i++) {
@@ -1176,6 +1221,9 @@ export class AbstractMatrix {
1176
1221
 
1177
1222
  setSubMatrix(matrix, startRow, startColumn) {
1178
1223
  matrix = Matrix.checkMatrix(matrix);
1224
+ if (matrix.isEmpty()) {
1225
+ return this;
1226
+ }
1179
1227
  let endRow = startRow + matrix.rows - 1;
1180
1228
  let endColumn = startColumn + matrix.columns - 1;
1181
1229
  checkRange(this, startRow, endRow, startColumn, endColumn);
@@ -1404,9 +1452,8 @@ export class AbstractMatrix {
1404
1452
 
1405
1453
  AbstractMatrix.prototype.klass = 'Matrix';
1406
1454
  if (typeof Symbol !== 'undefined') {
1407
- AbstractMatrix.prototype[
1408
- Symbol.for('nodejs.util.inspect.custom')
1409
- ] = inspectMatrix;
1455
+ AbstractMatrix.prototype[Symbol.for('nodejs.util.inspect.custom')] =
1456
+ inspectMatrix;
1410
1457
  }
1411
1458
 
1412
1459
  function compareNumbers(a, b) {
@@ -1429,10 +1476,10 @@ export default class Matrix extends AbstractMatrix {
1429
1476
  if (Matrix.isMatrix(nRows)) {
1430
1477
  // eslint-disable-next-line no-constructor-return
1431
1478
  return nRows.clone();
1432
- } else if (Number.isInteger(nRows) && nRows > 0) {
1479
+ } else if (Number.isInteger(nRows) && nRows >= 0) {
1433
1480
  // Create an empty matrix
1434
1481
  this.data = [];
1435
- if (Number.isInteger(nColumns) && nColumns > 0) {
1482
+ if (Number.isInteger(nColumns) && nColumns >= 0) {
1436
1483
  for (let i = 0; i < nRows; i++) {
1437
1484
  this.data.push(new Float64Array(nColumns));
1438
1485
  }
@@ -1443,8 +1490,8 @@ export default class Matrix extends AbstractMatrix {
1443
1490
  // Copy the values from the 2D array
1444
1491
  const arrayData = nRows;
1445
1492
  nRows = arrayData.length;
1446
- nColumns = arrayData[0].length;
1447
- if (typeof nColumns !== 'number' || nColumns === 0) {
1493
+ nColumns = nRows ? arrayData[0].length : 0;
1494
+ if (typeof nColumns !== 'number') {
1448
1495
  throw new TypeError(
1449
1496
  'Data must be a 2D array with at least one element',
1450
1497
  );
@@ -1476,9 +1523,6 @@ export default class Matrix extends AbstractMatrix {
1476
1523
 
1477
1524
  removeRow(index) {
1478
1525
  checkRowIndex(this, index);
1479
- if (this.rows === 1) {
1480
- throw new RangeError('A matrix cannot have less than one row');
1481
- }
1482
1526
  this.data.splice(index, 1);
1483
1527
  this.rows -= 1;
1484
1528
  return this;
@@ -1490,7 +1534,7 @@ export default class Matrix extends AbstractMatrix {
1490
1534
  index = this.rows;
1491
1535
  }
1492
1536
  checkRowIndex(this, index, true);
1493
- array = Float64Array.from(checkRowVector(this, array, true));
1537
+ array = Float64Array.from(checkRowVector(this, array));
1494
1538
  this.data.splice(index, 0, array);
1495
1539
  this.rows += 1;
1496
1540
  return this;
@@ -1498,9 +1542,6 @@ export default class Matrix extends AbstractMatrix {
1498
1542
 
1499
1543
  removeColumn(index) {
1500
1544
  checkColumnIndex(this, index);
1501
- if (this.columns === 1) {
1502
- throw new RangeError('A matrix cannot have less than one column');
1503
- }
1504
1545
  for (let i = 0; i < this.rows; i++) {
1505
1546
  const newRow = new Float64Array(this.columns - 1);
1506
1547
  for (let j = 0; j < index; j++) {
@@ -3,6 +3,12 @@ import Matrix from './matrix';
3
3
 
4
4
  export function pseudoInverse(matrix, threshold = Number.EPSILON) {
5
5
  matrix = Matrix.checkMatrix(matrix);
6
+ if (matrix.isEmpty()) {
7
+ // with a zero dimension, the pseudo-inverse is the transpose, since all 0xn and nx0 matrices are singular
8
+ // (0xn)*(nx0)*(0xn) = 0xn
9
+ // (nx0)*(0xn)*(nx0) = nx0
10
+ return matrix.transpose();
11
+ }
6
12
  let svdSolution = new SVD(matrix, { autoTranspose: true });
7
13
 
8
14
  let U = svdSolution.leftSingularVectors;
package/src/util.js CHANGED
@@ -143,3 +143,9 @@ function checkNumber(name, value) {
143
143
  throw new TypeError(`${name} must be a number`);
144
144
  }
145
145
  }
146
+
147
+ export function checkNonEmpty(matrix) {
148
+ if (matrix.isEmpty()) {
149
+ throw new Error('Empty matrix has no elements to index');
150
+ }
151
+ }