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/README.md CHANGED
@@ -1,11 +1,23 @@
1
1
  # ml-matrix
2
2
 
3
- [![NPM version][npm-image]][npm-url]
4
- [![build status][ci-image]][ci-url]
5
- [![npm download][download-image]][download-url]
6
-
7
3
  Matrix manipulation and computation library.
8
4
 
5
+ <h3 align="center">
6
+
7
+ <a href="https://www.zakodium.com">
8
+ <img src="https://www.zakodium.com/brand/zakodium-logo-white.svg" width="50" alt="Zakodium logo" />
9
+ </a>
10
+
11
+ <p>
12
+ Maintained by <a href="https://www.zakodium.com">Zakodium</a>
13
+ </p>
14
+
15
+ [![NPM version][npm-image]][npm-url]
16
+ [![build status][ci-image]][ci-url]
17
+ [![npm download][download-image]][download-url]
18
+
19
+ </h3>
20
+
9
21
  ## Installation
10
22
 
11
23
  `$ npm install ml-matrix`
@@ -47,7 +59,7 @@ var C = new Matrix([[3, 3], [1, 1]]);
47
59
 
48
60
  // operations :
49
61
  const addition = Matrix.add(A, B); // addition = Matrix [[4, 4], [3, 3], rows: 2, columns: 2]
50
- const substraction = Matrix.sub(A, B); // substraction = Matrix [[-2, -2], [1, 1], rows: 2, columns: 2]
62
+ const subtraction = Matrix.sub(A, B); // subtraction = Matrix [[-2, -2], [1, 1], rows: 2, columns: 2]
51
63
  const multiplication = A.mmul(B); // multiplication = Matrix [[4, 4], [8, 8], rows: 2, columns: 2]
52
64
  const mulByNumber = Matrix.mul(A, 10); // mulByNumber = Matrix [[10, 10], [20, 20], rows: 2, columns: 2]
53
65
  const divByNumber = Matrix.div(A, 10); // divByNumber = Matrix [[0.1, 0.1], [0.2, 0.2], rows: 2, columns: 2]
@@ -88,10 +100,10 @@ var diag = A.diag(); // diag = [1, -1], i.e values in the diagonal.
88
100
  var m = A.mean(); // m = 2.75
89
101
  var product = A.prod(); // product = -10, i.e product of all values of the matrix
90
102
  var norm = A.norm(); // norm = 10.14889156509222, i.e Frobenius norm of the matrix
91
- var transpose = A.transpose(); // tranpose = Matrix [[1, 10], [1, -1], rows: 2, columns: 2]
103
+ var transpose = A.transpose(); // transpose = Matrix [[1, 10], [1, -1], rows: 2, columns: 2]
92
104
 
93
105
  // ============================
94
- // Instanciation of matrix :
106
+ // Instantiation of matrix :
95
107
  // =============================
96
108
 
97
109
  var z = Matrix.zeros(3, 2); // z = Matrix [[0, 0], [0, 0], [0, 0], rows: 3, columns: 2]
@@ -110,6 +122,7 @@ const {
110
122
  QrDecomposition,
111
123
  LuDecomposition,
112
124
  CholeskyDecomposition,
125
+ EigenvalueDecomposition
113
126
  } = require('ml-matrix');
114
127
 
115
128
  //===========================
package/matrix.d.ts CHANGED
@@ -304,6 +304,11 @@ export abstract class AbstractMatrix {
304
304
  */
305
305
  isSquare(): boolean;
306
306
 
307
+ /**
308
+ * Returns whether the number of rows or columns (or both) is zero.
309
+ */
310
+ isEmpty(): boolean;
311
+
307
312
  /**
308
313
  * Returns whether the matrix is square and has the same values on both sides of the diagonal.
309
314
  */
@@ -603,6 +608,13 @@ export abstract class AbstractMatrix {
603
608
  * @param other - Other matrix.
604
609
  */
605
610
  kroneckerProduct(other: MaybeMatrix): Matrix;
611
+
612
+ /**
613
+ * Returns the Kronecker sum between `this` and `other`.
614
+ * @link https://en.wikipedia.org/wiki/Kronecker_product#Kronecker_sum
615
+ * @param other - Other matrix.
616
+ */
617
+ kroneckerSum(other: MaybeMatrix): Matrix;
606
618
 
607
619
  /**
608
620
  * Alias for {@link AbstractMatrix.kroneckerProduct}.
@@ -1216,7 +1228,7 @@ export interface INipalsOptions {
1216
1228
  * The maximum number of allowed iterations before beraking the loop if convergence is not achieved.
1217
1229
  * @default 1000
1218
1230
  */
1219
- maxIterations?: boolean;
1231
+ maxIterations?: number;
1220
1232
  /**
1221
1233
  * Termination criteria
1222
1234
  * @default 1e-10
@@ -1237,13 +1249,13 @@ export class Nipals {
1237
1249
  constructor(X: MaybeMatrix, options?: INipalsOptions);
1238
1250
  w: Matrix;
1239
1251
  s: Matrix;
1240
- t: number;
1252
+ t: Matrix;
1241
1253
  xResidual: Matrix;
1242
1254
  p: Matrix;
1243
1255
  q: Matrix;
1244
- u: number;
1256
+ u: Matrix;
1245
1257
  yResidual: Matrix;
1246
- betas: number;
1258
+ betas: Matrix;
1247
1259
  }
1248
1260
 
1249
1261
  export { Nipals as NIPALS };
package/matrix.js CHANGED
@@ -1032,6 +1032,12 @@ function checkNumber(name, value) {
1032
1032
  }
1033
1033
  }
1034
1034
 
1035
+ function checkNonEmpty(matrix) {
1036
+ if (matrix.isEmpty()) {
1037
+ throw new Error('Empty matrix has no elements to index');
1038
+ }
1039
+ }
1040
+
1035
1041
  function sumByRow(matrix) {
1036
1042
  let sum = newArray(matrix.rows);
1037
1043
  for (let i = 0; i < matrix.rows; ++i) {
@@ -1431,6 +1437,10 @@ class AbstractMatrix {
1431
1437
  return this.rows === this.columns;
1432
1438
  }
1433
1439
 
1440
+ isEmpty() {
1441
+ return this.rows === 0 || this.columns === 0;
1442
+ }
1443
+
1434
1444
  isSymmetric() {
1435
1445
  if (this.isSquare()) {
1436
1446
  for (let i = 0; i < this.rows; i++) {
@@ -1768,6 +1778,9 @@ class AbstractMatrix {
1768
1778
  }
1769
1779
 
1770
1780
  max() {
1781
+ if (this.isEmpty()) {
1782
+ return NaN;
1783
+ }
1771
1784
  let v = this.get(0, 0);
1772
1785
  for (let i = 0; i < this.rows; i++) {
1773
1786
  for (let j = 0; j < this.columns; j++) {
@@ -1780,6 +1793,7 @@ class AbstractMatrix {
1780
1793
  }
1781
1794
 
1782
1795
  maxIndex() {
1796
+ checkNonEmpty(this);
1783
1797
  let v = this.get(0, 0);
1784
1798
  let idx = [0, 0];
1785
1799
  for (let i = 0; i < this.rows; i++) {
@@ -1795,6 +1809,9 @@ class AbstractMatrix {
1795
1809
  }
1796
1810
 
1797
1811
  min() {
1812
+ if (this.isEmpty()) {
1813
+ return NaN;
1814
+ }
1798
1815
  let v = this.get(0, 0);
1799
1816
  for (let i = 0; i < this.rows; i++) {
1800
1817
  for (let j = 0; j < this.columns; j++) {
@@ -1807,6 +1824,7 @@ class AbstractMatrix {
1807
1824
  }
1808
1825
 
1809
1826
  minIndex() {
1827
+ checkNonEmpty(this);
1810
1828
  let v = this.get(0, 0);
1811
1829
  let idx = [0, 0];
1812
1830
  for (let i = 0; i < this.rows; i++) {
@@ -1823,6 +1841,9 @@ class AbstractMatrix {
1823
1841
 
1824
1842
  maxRow(row) {
1825
1843
  checkRowIndex(this, row);
1844
+ if (this.isEmpty()) {
1845
+ return NaN;
1846
+ }
1826
1847
  let v = this.get(row, 0);
1827
1848
  for (let i = 1; i < this.columns; i++) {
1828
1849
  if (this.get(row, i) > v) {
@@ -1834,6 +1855,7 @@ class AbstractMatrix {
1834
1855
 
1835
1856
  maxRowIndex(row) {
1836
1857
  checkRowIndex(this, row);
1858
+ checkNonEmpty(this);
1837
1859
  let v = this.get(row, 0);
1838
1860
  let idx = [row, 0];
1839
1861
  for (let i = 1; i < this.columns; i++) {
@@ -1847,6 +1869,9 @@ class AbstractMatrix {
1847
1869
 
1848
1870
  minRow(row) {
1849
1871
  checkRowIndex(this, row);
1872
+ if (this.isEmpty()) {
1873
+ return NaN;
1874
+ }
1850
1875
  let v = this.get(row, 0);
1851
1876
  for (let i = 1; i < this.columns; i++) {
1852
1877
  if (this.get(row, i) < v) {
@@ -1858,6 +1883,7 @@ class AbstractMatrix {
1858
1883
 
1859
1884
  minRowIndex(row) {
1860
1885
  checkRowIndex(this, row);
1886
+ checkNonEmpty(this);
1861
1887
  let v = this.get(row, 0);
1862
1888
  let idx = [row, 0];
1863
1889
  for (let i = 1; i < this.columns; i++) {
@@ -1871,6 +1897,9 @@ class AbstractMatrix {
1871
1897
 
1872
1898
  maxColumn(column) {
1873
1899
  checkColumnIndex(this, column);
1900
+ if (this.isEmpty()) {
1901
+ return NaN;
1902
+ }
1874
1903
  let v = this.get(0, column);
1875
1904
  for (let i = 1; i < this.rows; i++) {
1876
1905
  if (this.get(i, column) > v) {
@@ -1882,6 +1911,7 @@ class AbstractMatrix {
1882
1911
 
1883
1912
  maxColumnIndex(column) {
1884
1913
  checkColumnIndex(this, column);
1914
+ checkNonEmpty(this);
1885
1915
  let v = this.get(0, column);
1886
1916
  let idx = [0, column];
1887
1917
  for (let i = 1; i < this.rows; i++) {
@@ -1895,6 +1925,9 @@ class AbstractMatrix {
1895
1925
 
1896
1926
  minColumn(column) {
1897
1927
  checkColumnIndex(this, column);
1928
+ if (this.isEmpty()) {
1929
+ return NaN;
1930
+ }
1898
1931
  let v = this.get(0, column);
1899
1932
  for (let i = 1; i < this.rows; i++) {
1900
1933
  if (this.get(i, column) < v) {
@@ -1906,6 +1939,7 @@ class AbstractMatrix {
1906
1939
 
1907
1940
  minColumnIndex(column) {
1908
1941
  checkColumnIndex(this, column);
1942
+ checkNonEmpty(this);
1909
1943
  let v = this.get(0, column);
1910
1944
  let idx = [0, column];
1911
1945
  for (let i = 1; i < this.rows; i++) {
@@ -2224,7 +2258,9 @@ class AbstractMatrix {
2224
2258
  let newMatrix = new Matrix(this.rows, this.columns);
2225
2259
  for (let i = 0; i < this.rows; i++) {
2226
2260
  const row = this.getRow(i);
2227
- rescale__default['default'](row, { min, max, output: row });
2261
+ if (row.length > 0) {
2262
+ rescale__default["default"](row, { min, max, output: row });
2263
+ }
2228
2264
  newMatrix.setRow(i, row);
2229
2265
  }
2230
2266
  return newMatrix;
@@ -2241,11 +2277,13 @@ class AbstractMatrix {
2241
2277
  let newMatrix = new Matrix(this.rows, this.columns);
2242
2278
  for (let i = 0; i < this.columns; i++) {
2243
2279
  const column = this.getColumn(i);
2244
- rescale__default['default'](column, {
2245
- min: min,
2246
- max: max,
2247
- output: column,
2248
- });
2280
+ if (column.length) {
2281
+ rescale__default["default"](column, {
2282
+ min: min,
2283
+ max: max,
2284
+ output: column,
2285
+ });
2286
+ }
2249
2287
  newMatrix.setColumn(i, column);
2250
2288
  }
2251
2289
  return newMatrix;
@@ -2298,6 +2336,18 @@ class AbstractMatrix {
2298
2336
  return result;
2299
2337
  }
2300
2338
 
2339
+ kroneckerSum(other) {
2340
+ other = Matrix.checkMatrix(other);
2341
+ if (!this.isSquare() || !other.isSquare()) {
2342
+ throw new Error('Kronecker Sum needs two Square Matrices');
2343
+ }
2344
+ let m = this.rows;
2345
+ let n = other.rows;
2346
+ let AxI = this.kroneckerProduct(Matrix.eye(n, n));
2347
+ let IxB = Matrix.eye(m, m).kroneckerProduct(other);
2348
+ return AxI.add(IxB);
2349
+ }
2350
+
2301
2351
  transpose() {
2302
2352
  let result = new Matrix(this.columns, this.rows);
2303
2353
  for (let i = 0; i < this.rows; i++) {
@@ -2388,6 +2438,9 @@ class AbstractMatrix {
2388
2438
 
2389
2439
  setSubMatrix(matrix, startRow, startColumn) {
2390
2440
  matrix = Matrix.checkMatrix(matrix);
2441
+ if (matrix.isEmpty()) {
2442
+ return this;
2443
+ }
2391
2444
  let endRow = startRow + matrix.rows - 1;
2392
2445
  let endColumn = startColumn + matrix.columns - 1;
2393
2446
  checkRange(this, startRow, endRow, startColumn, endColumn);
@@ -2616,9 +2669,8 @@ class AbstractMatrix {
2616
2669
 
2617
2670
  AbstractMatrix.prototype.klass = 'Matrix';
2618
2671
  if (typeof Symbol !== 'undefined') {
2619
- AbstractMatrix.prototype[
2620
- Symbol.for('nodejs.util.inspect.custom')
2621
- ] = inspectMatrix;
2672
+ AbstractMatrix.prototype[Symbol.for('nodejs.util.inspect.custom')] =
2673
+ inspectMatrix;
2622
2674
  }
2623
2675
 
2624
2676
  function compareNumbers(a, b) {
@@ -2641,10 +2693,10 @@ class Matrix extends AbstractMatrix {
2641
2693
  if (Matrix.isMatrix(nRows)) {
2642
2694
  // eslint-disable-next-line no-constructor-return
2643
2695
  return nRows.clone();
2644
- } else if (Number.isInteger(nRows) && nRows > 0) {
2696
+ } else if (Number.isInteger(nRows) && nRows >= 0) {
2645
2697
  // Create an empty matrix
2646
2698
  this.data = [];
2647
- if (Number.isInteger(nColumns) && nColumns > 0) {
2699
+ if (Number.isInteger(nColumns) && nColumns >= 0) {
2648
2700
  for (let i = 0; i < nRows; i++) {
2649
2701
  this.data.push(new Float64Array(nColumns));
2650
2702
  }
@@ -2655,8 +2707,8 @@ class Matrix extends AbstractMatrix {
2655
2707
  // Copy the values from the 2D array
2656
2708
  const arrayData = nRows;
2657
2709
  nRows = arrayData.length;
2658
- nColumns = arrayData[0].length;
2659
- if (typeof nColumns !== 'number' || nColumns === 0) {
2710
+ nColumns = nRows ? arrayData[0].length : 0;
2711
+ if (typeof nColumns !== 'number') {
2660
2712
  throw new TypeError(
2661
2713
  'Data must be a 2D array with at least one element',
2662
2714
  );
@@ -2688,9 +2740,6 @@ class Matrix extends AbstractMatrix {
2688
2740
 
2689
2741
  removeRow(index) {
2690
2742
  checkRowIndex(this, index);
2691
- if (this.rows === 1) {
2692
- throw new RangeError('A matrix cannot have less than one row');
2693
- }
2694
2743
  this.data.splice(index, 1);
2695
2744
  this.rows -= 1;
2696
2745
  return this;
@@ -2710,9 +2759,6 @@ class Matrix extends AbstractMatrix {
2710
2759
 
2711
2760
  removeColumn(index) {
2712
2761
  checkColumnIndex(this, index);
2713
- if (this.columns === 1) {
2714
- throw new RangeError('A matrix cannot have less than one column');
2715
- }
2716
2762
  for (let i = 0; i < this.rows; i++) {
2717
2763
  const newRow = new Float64Array(this.columns - 1);
2718
2764
  for (let j = 0; j < index; j++) {
@@ -3315,6 +3361,10 @@ class SingularValueDecomposition {
3315
3361
  constructor(value, options = {}) {
3316
3362
  value = WrapperMatrix2D.checkMatrix(value);
3317
3363
 
3364
+ if (value.isEmpty()) {
3365
+ throw new Error('Matrix must be non-empty');
3366
+ }
3367
+
3318
3368
  let m = value.rows;
3319
3369
  let n = value.columns;
3320
3370
 
@@ -3851,6 +3901,10 @@ function solve(leftHandSide, rightHandSide, useSVD = false) {
3851
3901
  function determinant(matrix) {
3852
3902
  matrix = Matrix.checkMatrix(matrix);
3853
3903
  if (matrix.isSquare()) {
3904
+ if (matrix.columns === 0) {
3905
+ return 1;
3906
+ }
3907
+
3854
3908
  let a, b, c, d;
3855
3909
  if (matrix.columns === 2) {
3856
3910
  // 2 x 2 matrix
@@ -3937,6 +3991,12 @@ function linearDependencies(matrix, options = {}) {
3937
3991
 
3938
3992
  function pseudoInverse(matrix, threshold = Number.EPSILON) {
3939
3993
  matrix = Matrix.checkMatrix(matrix);
3994
+ if (matrix.isEmpty()) {
3995
+ // with a zero dimension, the pseudo-inverse is the transpose, since all 0xn and nx0 matrices are singular
3996
+ // (0xn)*(nx0)*(0xn) = 0xn
3997
+ // (nx0)*(0xn)*(nx0) = nx0
3998
+ return matrix.transpose();
3999
+ }
3940
4000
  let svdSolution = new SingularValueDecomposition(matrix, { autoTranspose: true });
3941
4001
 
3942
4002
  let U = svdSolution.leftSingularVectors;
@@ -4046,6 +4106,10 @@ class EigenvalueDecomposition {
4046
4106
  throw new Error('Matrix is not a square matrix');
4047
4107
  }
4048
4108
 
4109
+ if (matrix.isEmpty()) {
4110
+ throw new Error('Matrix must be non-empty');
4111
+ }
4112
+
4049
4113
  let n = matrix.columns;
4050
4114
  let V = new Matrix(n, n);
4051
4115
  let d = new Float64Array(n);
@@ -4930,10 +4994,10 @@ class nipals {
4930
4994
  } else {
4931
4995
  Y = WrapperMatrix2D.checkMatrix(Y);
4932
4996
  }
4933
- if (!Y.isColumnVector() || Y.rows !== X.rows) {
4934
- throw new Error('Y must be a column vector of length X.rows');
4997
+ if (Y.rows !== X.rows) {
4998
+ throw new Error('Y should have the same number of rows as X');
4935
4999
  }
4936
- u = Y;
5000
+ u = Y.getColumnVector(0);
4937
5001
  } else {
4938
5002
  u = X.getColumnVector(0);
4939
5003
  }
@@ -5024,7 +5088,7 @@ exports.WrapperMatrix1D = WrapperMatrix1D;
5024
5088
  exports.WrapperMatrix2D = WrapperMatrix2D;
5025
5089
  exports.correlation = correlation;
5026
5090
  exports.covariance = covariance;
5027
- exports.default = Matrix;
5091
+ exports["default"] = Matrix;
5028
5092
  exports.determinant = determinant;
5029
5093
  exports.inverse = inverse;
5030
5094
  exports.linearDependencies = linearDependencies;