ml-matrix 6.10.8 → 6.11.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/matrix.js CHANGED
@@ -8,6 +8,10 @@ var rescale = require('ml-array-rescale');
8
8
  const indent = ' '.repeat(2);
9
9
  const indentData = ' '.repeat(4);
10
10
 
11
+ /**
12
+ * @this {Matrix}
13
+ * @returns {string}
14
+ */
11
15
  function inspectMatrix() {
12
16
  return inspectMatrixWithOptions(this);
13
17
  }
@@ -900,7 +904,7 @@ function installMathOperations(AbstractMatrix, Matrix) {
900
904
  AbstractMatrix.prototype.powS = function powS(value) {
901
905
  for (let i = 0; i < this.rows; i++) {
902
906
  for (let j = 0; j < this.columns; j++) {
903
- this.set(i, j, Math.pow(this.get(i, j), value));
907
+ this.set(i, j, this.get(i, j) ** value);
904
908
  }
905
909
  }
906
910
  return this;
@@ -914,7 +918,7 @@ function installMathOperations(AbstractMatrix, Matrix) {
914
918
  }
915
919
  for (let i = 0; i < this.rows; i++) {
916
920
  for (let j = 0; j < this.columns; j++) {
917
- this.set(i, j, Math.pow(this.get(i, j), matrix.get(i, j)));
921
+ this.set(i, j, this.get(i, j) ** matrix.get(i, j));
918
922
  }
919
923
  }
920
924
  return this;
@@ -1212,7 +1216,7 @@ function getScaleByRow(matrix) {
1212
1216
  for (let i = 0; i < matrix.rows; i++) {
1213
1217
  let sum = 0;
1214
1218
  for (let j = 0; j < matrix.columns; j++) {
1215
- sum += Math.pow(matrix.get(i, j), 2) / (matrix.columns - 1);
1219
+ sum += matrix.get(i, j) ** 2 / (matrix.columns - 1);
1216
1220
  }
1217
1221
  scale.push(Math.sqrt(sum));
1218
1222
  }
@@ -1232,7 +1236,7 @@ function getScaleByColumn(matrix) {
1232
1236
  for (let j = 0; j < matrix.columns; j++) {
1233
1237
  let sum = 0;
1234
1238
  for (let i = 0; i < matrix.rows; i++) {
1235
- sum += Math.pow(matrix.get(i, j), 2) / (matrix.rows - 1);
1239
+ sum += matrix.get(i, j) ** 2 / (matrix.rows - 1);
1236
1240
  }
1237
1241
  scale.push(Math.sqrt(sum));
1238
1242
  }
@@ -1252,7 +1256,7 @@ function getScaleAll(matrix) {
1252
1256
  let sum = 0;
1253
1257
  for (let j = 0; j < matrix.columns; j++) {
1254
1258
  for (let i = 0; i < matrix.rows; i++) {
1255
- sum += Math.pow(matrix.get(i, j), 2) / divider;
1259
+ sum += matrix.get(i, j) ** 2 / divider;
1256
1260
  }
1257
1261
  }
1258
1262
  return Math.sqrt(sum);
@@ -1472,6 +1476,16 @@ class AbstractMatrix {
1472
1476
  return false;
1473
1477
  }
1474
1478
 
1479
+ isDistance() {
1480
+ if (!this.isSymmetric()) return false;
1481
+
1482
+ for (let i = 0; i < this.rows; i++) {
1483
+ if (this.get(i, i) !== 0) return false;
1484
+ }
1485
+
1486
+ return true;
1487
+ }
1488
+
1475
1489
  isEchelonForm() {
1476
1490
  let i = 0;
1477
1491
  let j = 0;
@@ -2546,13 +2560,21 @@ class AbstractMatrix {
2546
2560
  }
2547
2561
 
2548
2562
  clone() {
2549
- let newMatrix = new Matrix(this.rows, this.columns);
2550
- for (let row = 0; row < this.rows; row++) {
2551
- for (let column = 0; column < this.columns; column++) {
2552
- newMatrix.set(row, column, this.get(row, column));
2553
- }
2563
+ return this.constructor.copy(this, new Matrix(this.rows, this.columns));
2564
+ }
2565
+
2566
+ /**
2567
+ * @template {AbstractMatrix} M
2568
+ * @param {AbstractMatrix} from
2569
+ * @param {M} to
2570
+ * @return {M}
2571
+ */
2572
+ static copy(from, to) {
2573
+ for (const [row, column, value] of from.entries()) {
2574
+ to.set(row, column, value);
2554
2575
  }
2555
- return newMatrix;
2576
+
2577
+ return to;
2556
2578
  }
2557
2579
 
2558
2580
  sum(by) {
@@ -2736,6 +2758,36 @@ class AbstractMatrix {
2736
2758
  toString(options) {
2737
2759
  return inspectMatrixWithOptions(this, options);
2738
2760
  }
2761
+
2762
+ [Symbol.iterator]() {
2763
+ return this.entries();
2764
+ }
2765
+
2766
+ /**
2767
+ * iterator from left to right, from top to bottom
2768
+ * yield [row, column, value]
2769
+ * @returns {Generator<[number, number, number], void, *>}
2770
+ */
2771
+ *entries() {
2772
+ for (let row = 0; row < this.rows; row++) {
2773
+ for (let col = 0; col < this.columns; col++) {
2774
+ yield [row, col, this.get(row, col)];
2775
+ }
2776
+ }
2777
+ }
2778
+
2779
+ /**
2780
+ * iterator from left to right, from top to bottom
2781
+ * yield value
2782
+ * @returns {Generator<number, void, *>}
2783
+ */
2784
+ *values() {
2785
+ for (let row = 0; row < this.rows; row++) {
2786
+ for (let col = 0; col < this.columns; col++) {
2787
+ yield this.get(row, col);
2788
+ }
2789
+ }
2790
+ }
2739
2791
  }
2740
2792
 
2741
2793
  AbstractMatrix.prototype.klass = 'Matrix';
@@ -2765,21 +2817,38 @@ AbstractMatrix.prototype.tensorProduct =
2765
2817
  AbstractMatrix.prototype.kroneckerProduct;
2766
2818
 
2767
2819
  class Matrix extends AbstractMatrix {
2820
+ /**
2821
+ * @type {Float64Array[]}
2822
+ */
2823
+ data;
2824
+
2825
+ /**
2826
+ * Init an empty matrix
2827
+ * @param {number} nRows
2828
+ * @param {number} nColumns
2829
+ */
2830
+ #initData(nRows, nColumns) {
2831
+ this.data = [];
2832
+
2833
+ if (Number.isInteger(nColumns) && nColumns >= 0) {
2834
+ for (let i = 0; i < nRows; i++) {
2835
+ this.data.push(new Float64Array(nColumns));
2836
+ }
2837
+ } else {
2838
+ throw new TypeError('nColumns must be a positive integer');
2839
+ }
2840
+
2841
+ this.rows = nRows;
2842
+ this.columns = nColumns;
2843
+ }
2844
+
2768
2845
  constructor(nRows, nColumns) {
2769
2846
  super();
2770
2847
  if (Matrix.isMatrix(nRows)) {
2771
- // eslint-disable-next-line no-constructor-return
2772
- return nRows.clone();
2848
+ this.#initData(nRows.rows, nRows.columns);
2849
+ Matrix.copy(nRows, this);
2773
2850
  } else if (Number.isInteger(nRows) && nRows >= 0) {
2774
- // Create an empty matrix
2775
- this.data = [];
2776
- if (Number.isInteger(nColumns) && nColumns >= 0) {
2777
- for (let i = 0; i < nRows; i++) {
2778
- this.data.push(new Float64Array(nColumns));
2779
- }
2780
- } else {
2781
- throw new TypeError('nColumns must be a positive integer');
2782
- }
2851
+ this.#initData(nRows, nColumns);
2783
2852
  } else if (isAnyArray.isAnyArray(nRows)) {
2784
2853
  // Copy the values from the 2D array
2785
2854
  const arrayData = nRows;
@@ -2791,6 +2860,7 @@ class Matrix extends AbstractMatrix {
2791
2860
  );
2792
2861
  }
2793
2862
  this.data = [];
2863
+
2794
2864
  for (let i = 0; i < nRows; i++) {
2795
2865
  if (arrayData[i].length !== nColumns) {
2796
2866
  throw new RangeError('Inconsistent array dimensions');
@@ -2800,13 +2870,14 @@ class Matrix extends AbstractMatrix {
2800
2870
  }
2801
2871
  this.data.push(Float64Array.from(arrayData[i]));
2802
2872
  }
2873
+
2874
+ this.rows = nRows;
2875
+ this.columns = nColumns;
2803
2876
  } else {
2804
2877
  throw new TypeError(
2805
2878
  'First argument must be a positive number or an array',
2806
2879
  );
2807
2880
  }
2808
- this.rows = nRows;
2809
- this.columns = nColumns;
2810
2881
  }
2811
2882
 
2812
2883
  set(rowIndex, columnIndex, value) {
@@ -2879,6 +2950,380 @@ class Matrix extends AbstractMatrix {
2879
2950
 
2880
2951
  installMathOperations(AbstractMatrix, Matrix);
2881
2952
 
2953
+ /**
2954
+ * @typedef {0 | 1 | number | boolean} Mask
2955
+ */
2956
+
2957
+ class SymmetricMatrix extends AbstractMatrix {
2958
+ /** @type {Matrix} */
2959
+ #matrix;
2960
+
2961
+ get size() {
2962
+ return this.#matrix.size;
2963
+ }
2964
+
2965
+ get rows() {
2966
+ return this.#matrix.rows;
2967
+ }
2968
+
2969
+ get columns() {
2970
+ return this.#matrix.columns;
2971
+ }
2972
+
2973
+ get diagonalSize() {
2974
+ return this.rows;
2975
+ }
2976
+
2977
+ /**
2978
+ * not the same as matrix.isSymmetric()
2979
+ * Here is to check if it's instanceof SymmetricMatrix without bundling issues
2980
+ *
2981
+ * @param value
2982
+ * @returns {boolean}
2983
+ */
2984
+ static isSymmetricMatrix(value) {
2985
+ return Matrix.isMatrix(value) && value.klassType === 'SymmetricMatrix';
2986
+ }
2987
+
2988
+ /**
2989
+ * @param diagonalSize
2990
+ * @return {SymmetricMatrix}
2991
+ */
2992
+ static zeros(diagonalSize) {
2993
+ return new this(diagonalSize);
2994
+ }
2995
+
2996
+ /**
2997
+ * @param diagonalSize
2998
+ * @return {SymmetricMatrix}
2999
+ */
3000
+ static ones(diagonalSize) {
3001
+ return new this(diagonalSize).fill(1);
3002
+ }
3003
+
3004
+ /**
3005
+ * @param {number | AbstractMatrix | ArrayLike<ArrayLike<number>>} diagonalSize
3006
+ * @return {this}
3007
+ */
3008
+ constructor(diagonalSize) {
3009
+ super();
3010
+
3011
+ if (Matrix.isMatrix(diagonalSize)) {
3012
+ if (!diagonalSize.isSymmetric()) {
3013
+ throw new TypeError('not symmetric data');
3014
+ }
3015
+
3016
+ this.#matrix = Matrix.copy(
3017
+ diagonalSize,
3018
+ new Matrix(diagonalSize.rows, diagonalSize.rows),
3019
+ );
3020
+ } else if (Number.isInteger(diagonalSize) && diagonalSize >= 0) {
3021
+ this.#matrix = new Matrix(diagonalSize, diagonalSize);
3022
+ } else {
3023
+ this.#matrix = new Matrix(diagonalSize);
3024
+
3025
+ if (!this.isSymmetric()) {
3026
+ throw new TypeError('not symmetric data');
3027
+ }
3028
+ }
3029
+ }
3030
+
3031
+ clone() {
3032
+ const matrix = new SymmetricMatrix(this.diagonalSize);
3033
+
3034
+ for (const [row, col, value] of this.upperRightEntries()) {
3035
+ matrix.set(row, col, value);
3036
+ }
3037
+
3038
+ return matrix;
3039
+ }
3040
+
3041
+ toMatrix() {
3042
+ return new Matrix(this);
3043
+ }
3044
+
3045
+ get(rowIndex, columnIndex) {
3046
+ return this.#matrix.get(rowIndex, columnIndex);
3047
+ }
3048
+ set(rowIndex, columnIndex, value) {
3049
+ // symmetric set
3050
+ this.#matrix.set(rowIndex, columnIndex, value);
3051
+ this.#matrix.set(columnIndex, rowIndex, value);
3052
+
3053
+ return this;
3054
+ }
3055
+
3056
+ removeCross(index) {
3057
+ // symmetric remove side
3058
+ this.#matrix.removeRow(index);
3059
+ this.#matrix.removeColumn(index);
3060
+
3061
+ return this;
3062
+ }
3063
+
3064
+ addCross(index, array) {
3065
+ if (array === undefined) {
3066
+ array = index;
3067
+ index = this.diagonalSize;
3068
+ }
3069
+
3070
+ const row = array.slice();
3071
+ row.splice(index, 1);
3072
+
3073
+ this.#matrix.addRow(index, row);
3074
+ this.#matrix.addColumn(index, array);
3075
+
3076
+ return this;
3077
+ }
3078
+
3079
+ /**
3080
+ * @param {Mask[]} mask
3081
+ */
3082
+ applyMask(mask) {
3083
+ if (mask.length !== this.diagonalSize) {
3084
+ throw new RangeError('Mask size do not match with matrix size');
3085
+ }
3086
+
3087
+ // prepare sides to remove from matrix from mask
3088
+ /** @type {number[]} */
3089
+ const sidesToRemove = [];
3090
+ for (const [index, passthroughs] of mask.entries()) {
3091
+ if (passthroughs) continue;
3092
+ sidesToRemove.push(index);
3093
+ }
3094
+ // to remove from highest to lowest for no mutation shifting
3095
+ sidesToRemove.reverse();
3096
+
3097
+ // remove sides
3098
+ for (const sideIndex of sidesToRemove) {
3099
+ this.removeCross(sideIndex);
3100
+ }
3101
+
3102
+ return this;
3103
+ }
3104
+
3105
+ /**
3106
+ * Compact format upper-right corner of matrix
3107
+ * iterate from left to right, from top to bottom.
3108
+ *
3109
+ * ```
3110
+ * A B C D
3111
+ * A 1 2 3 4
3112
+ * B 2 5 6 7
3113
+ * C 3 6 8 9
3114
+ * D 4 7 9 10
3115
+ * ```
3116
+ *
3117
+ * will return compact 1D array `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`
3118
+ *
3119
+ * length is S(i=0, n=sideSize) => 10 for a 4 sideSized matrix
3120
+ *
3121
+ * @returns {number[]}
3122
+ */
3123
+ toCompact() {
3124
+ const { diagonalSize } = this;
3125
+
3126
+ /** @type {number[]} */
3127
+ const compact = new Array((diagonalSize * (diagonalSize + 1)) / 2);
3128
+ for (let col = 0, row = 0, index = 0; index < compact.length; index++) {
3129
+ compact[index] = this.get(row, col);
3130
+
3131
+ if (++col >= diagonalSize) col = ++row;
3132
+ }
3133
+
3134
+ return compact;
3135
+ }
3136
+
3137
+ /**
3138
+ * @param {number[]} compact
3139
+ * @return {SymmetricMatrix}
3140
+ */
3141
+ static fromCompact(compact) {
3142
+ const compactSize = compact.length;
3143
+ // compactSize = (sideSize * (sideSize + 1)) / 2
3144
+ // https://mathsolver.microsoft.com/fr/solve-problem/y%20%3D%20%20x%20%60cdot%20%20%20%60frac%7B%20%20%60left(%20x%2B1%20%20%60right)%20%20%20%20%7D%7B%202%20%20%7D
3145
+ // sideSize = (Sqrt(8 × compactSize + 1) - 1) / 2
3146
+ const diagonalSize = (Math.sqrt(8 * compactSize + 1) - 1) / 2;
3147
+
3148
+ if (!Number.isInteger(diagonalSize)) {
3149
+ throw new TypeError(
3150
+ `This array is not a compact representation of a Symmetric Matrix, ${JSON.stringify(
3151
+ compact,
3152
+ )}`,
3153
+ );
3154
+ }
3155
+
3156
+ const matrix = new SymmetricMatrix(diagonalSize);
3157
+ for (let col = 0, row = 0, index = 0; index < compactSize; index++) {
3158
+ matrix.set(col, row, compact[index]);
3159
+ if (++col >= diagonalSize) col = ++row;
3160
+ }
3161
+
3162
+ return matrix;
3163
+ }
3164
+
3165
+ /**
3166
+ * half iterator upper-right-corner from left to right, from top to bottom
3167
+ * yield [row, column, value]
3168
+ *
3169
+ * @returns {Generator<[number, number, number], void, *>}
3170
+ */
3171
+ *upperRightEntries() {
3172
+ for (let row = 0, col = 0; row < this.diagonalSize; void 0) {
3173
+ const value = this.get(row, col);
3174
+
3175
+ yield [row, col, value];
3176
+
3177
+ // at the end of row, move cursor to next row at diagonal position
3178
+ if (++col >= this.diagonalSize) col = ++row;
3179
+ }
3180
+ }
3181
+
3182
+ /**
3183
+ * half iterator upper-right-corner from left to right, from top to bottom
3184
+ * yield value
3185
+ *
3186
+ * @returns {Generator<[number, number, number], void, *>}
3187
+ */
3188
+ *upperRightValues() {
3189
+ for (let row = 0, col = 0; row < this.diagonalSize; void 0) {
3190
+ const value = this.get(row, col);
3191
+
3192
+ yield value;
3193
+
3194
+ // at the end of row, move cursor to next row at diagonal position
3195
+ if (++col >= this.diagonalSize) col = ++row;
3196
+ }
3197
+ }
3198
+ }
3199
+ SymmetricMatrix.prototype.klassType = 'SymmetricMatrix';
3200
+
3201
+ class DistanceMatrix extends SymmetricMatrix {
3202
+ /**
3203
+ * not the same as matrix.isSymmetric()
3204
+ * Here is to check if it's instanceof SymmetricMatrix without bundling issues
3205
+ *
3206
+ * @param value
3207
+ * @returns {boolean}
3208
+ */
3209
+ static isDistanceMatrix(value) {
3210
+ return (
3211
+ SymmetricMatrix.isSymmetricMatrix(value) &&
3212
+ value.klassSubType === 'DistanceMatrix'
3213
+ );
3214
+ }
3215
+
3216
+ constructor(sideSize) {
3217
+ super(sideSize);
3218
+
3219
+ if (!this.isDistance()) {
3220
+ throw new TypeError('Provided arguments do no produce a distance matrix');
3221
+ }
3222
+ }
3223
+
3224
+ set(rowIndex, columnIndex, value) {
3225
+ // distance matrix diagonal is 0
3226
+ if (rowIndex === columnIndex) value = 0;
3227
+
3228
+ return super.set(rowIndex, columnIndex, value);
3229
+ }
3230
+
3231
+ addCross(index, array) {
3232
+ if (array === undefined) {
3233
+ array = index;
3234
+ index = this.diagonalSize;
3235
+ }
3236
+
3237
+ // ensure distance
3238
+ array = array.slice();
3239
+ array[index] = 0;
3240
+
3241
+ return super.addCross(index, array);
3242
+ }
3243
+
3244
+ toSymmetricMatrix() {
3245
+ return new SymmetricMatrix(this);
3246
+ }
3247
+
3248
+ clone() {
3249
+ const matrix = new DistanceMatrix(this.diagonalSize);
3250
+
3251
+ for (const [row, col, value] of this.upperRightEntries()) {
3252
+ if (row === col) continue;
3253
+ matrix.set(row, col, value);
3254
+ }
3255
+
3256
+ return matrix;
3257
+ }
3258
+
3259
+ /**
3260
+ * Compact format upper-right corner of matrix
3261
+ * no diagonal (only zeros)
3262
+ * iterable from left to right, from top to bottom.
3263
+ *
3264
+ * ```
3265
+ * A B C D
3266
+ * A 0 1 2 3
3267
+ * B 1 0 4 5
3268
+ * C 2 4 0 6
3269
+ * D 3 5 6 0
3270
+ * ```
3271
+ *
3272
+ * will return compact 1D array `[1, 2, 3, 4, 5, 6]`
3273
+ *
3274
+ * length is S(i=0, n=sideSize-1) => 6 for a 4 side sized matrix
3275
+ *
3276
+ * @returns {number[]}
3277
+ */
3278
+ toCompact() {
3279
+ const { diagonalSize } = this;
3280
+ const compactLength = ((diagonalSize - 1) * diagonalSize) / 2;
3281
+
3282
+ /** @type {number[]} */
3283
+ const compact = new Array(compactLength);
3284
+ for (let col = 1, row = 0, index = 0; index < compact.length; index++) {
3285
+ compact[index] = this.get(row, col);
3286
+
3287
+ if (++col >= diagonalSize) col = ++row + 1;
3288
+ }
3289
+
3290
+ return compact;
3291
+ }
3292
+
3293
+ /**
3294
+ * @param {number[]} compact
3295
+ */
3296
+ static fromCompact(compact) {
3297
+ const compactSize = compact.length;
3298
+
3299
+ if (compactSize === 0) {
3300
+ return new this(0);
3301
+ }
3302
+
3303
+ // compactSize in Natural integer range ]0;∞]
3304
+ // compactSize = (sideSize * (sideSize - 1)) / 2
3305
+ // sideSize = (Sqrt(8 × compactSize + 1) + 1) / 2
3306
+ const diagonalSize = (Math.sqrt(8 * compactSize + 1) + 1) / 2;
3307
+
3308
+ if (!Number.isInteger(diagonalSize)) {
3309
+ throw new TypeError(
3310
+ `This array is not a compact representation of a DistanceMatrix, ${JSON.stringify(
3311
+ compact,
3312
+ )}`,
3313
+ );
3314
+ }
3315
+
3316
+ const matrix = new this(diagonalSize);
3317
+ for (let col = 1, row = 0, index = 0; index < compactSize; index++) {
3318
+ matrix.set(col, row, compact[index]);
3319
+ if (++col >= diagonalSize) col = ++row + 1;
3320
+ }
3321
+
3322
+ return matrix;
3323
+ }
3324
+ }
3325
+ DistanceMatrix.prototype.klassSubType = 'DistanceMatrix';
3326
+
2882
3327
  class BaseView extends AbstractMatrix {
2883
3328
  constructor(matrix, rows, columns) {
2884
3329
  super();
@@ -5147,6 +5592,7 @@ class nipals {
5147
5592
  exports.AbstractMatrix = AbstractMatrix;
5148
5593
  exports.CHO = CholeskyDecomposition;
5149
5594
  exports.CholeskyDecomposition = CholeskyDecomposition;
5595
+ exports.DistanceMatrix = DistanceMatrix;
5150
5596
  exports.EVD = EigenvalueDecomposition;
5151
5597
  exports.EigenvalueDecomposition = EigenvalueDecomposition;
5152
5598
  exports.LU = LuDecomposition;
@@ -5167,6 +5613,7 @@ exports.QR = QrDecomposition;
5167
5613
  exports.QrDecomposition = QrDecomposition;
5168
5614
  exports.SVD = SingularValueDecomposition;
5169
5615
  exports.SingularValueDecomposition = SingularValueDecomposition;
5616
+ exports.SymmetricMatrix = SymmetricMatrix;
5170
5617
  exports.WrapperMatrix1D = WrapperMatrix1D;
5171
5618
  exports.WrapperMatrix2D = WrapperMatrix2D;
5172
5619
  exports.correlation = correlation;
package/matrix.mjs CHANGED
@@ -3,6 +3,7 @@ import * as matrix from './matrix.js';
3
3
  export const AbstractMatrix = matrix.AbstractMatrix;
4
4
  export const CHO = matrix.CHO;
5
5
  export const CholeskyDecomposition = matrix.CholeskyDecomposition;
6
+ export const DistanceMatrix = matrix.DistanceMatrix;
6
7
  export const EVD = matrix.EVD;
7
8
  export const EigenvalueDecomposition = matrix.EigenvalueDecomposition;
8
9
  export const LU = matrix.LU;
@@ -23,6 +24,7 @@ export const QR = matrix.QR;
23
24
  export const QrDecomposition = matrix.QrDecomposition;
24
25
  export const SVD = matrix.SVD;
25
26
  export const SingularValueDecomposition = matrix.SingularValueDecomposition;
27
+ export const SymmetricMatrix = matrix.SymmetricMatrix;
26
28
  export const WrapperMatrix1D = matrix.WrapperMatrix1D;
27
29
  export const WrapperMatrix2D = matrix.WrapperMatrix2D;
28
30
  export const correlation = matrix.correlation;