ml-matrix 6.8.2 → 6.10.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
@@ -1,3 +1,4 @@
1
+ import { isAnyArray } from 'is-any-array';
1
2
  import rescale from 'ml-array-rescale';
2
3
 
3
4
  import { inspectMatrix, inspectMatrixWithOptions } from './inspect';
@@ -28,8 +29,9 @@ import {
28
29
  checkColumnIndex,
29
30
  checkColumnVector,
30
31
  checkRange,
31
- checkIndices,
32
32
  checkNonEmpty,
33
+ checkRowIndices,
34
+ checkColumnIndices,
33
35
  } from './util';
34
36
 
35
37
  export class AbstractMatrix {
@@ -560,19 +562,47 @@ export class AbstractMatrix {
560
562
  return this;
561
563
  }
562
564
 
563
- max() {
565
+ max(by) {
564
566
  if (this.isEmpty()) {
565
567
  return NaN;
566
568
  }
567
- let v = this.get(0, 0);
568
- for (let i = 0; i < this.rows; i++) {
569
- for (let j = 0; j < this.columns; j++) {
570
- if (this.get(i, j) > v) {
571
- v = this.get(i, j);
569
+ switch (by) {
570
+ case 'row': {
571
+ const max = new Array(this.rows).fill(Number.NEGATIVE_INFINITY);
572
+ for (let row = 0; row < this.rows; row++) {
573
+ for (let column = 0; column < this.columns; column++) {
574
+ if (this.get(row, column) > max[row]) {
575
+ max[row] = this.get(row, column);
576
+ }
577
+ }
572
578
  }
579
+ return max;
573
580
  }
581
+ case 'column': {
582
+ const max = new Array(this.columns).fill(Number.NEGATIVE_INFINITY);
583
+ for (let row = 0; row < this.rows; row++) {
584
+ for (let column = 0; column < this.columns; column++) {
585
+ if (this.get(row, column) > max[column]) {
586
+ max[column] = this.get(row, column);
587
+ }
588
+ }
589
+ }
590
+ return max;
591
+ }
592
+ case undefined: {
593
+ let max = this.get(0, 0);
594
+ for (let row = 0; row < this.rows; row++) {
595
+ for (let column = 0; column < this.columns; column++) {
596
+ if (this.get(row, column) > max) {
597
+ max = this.get(row, column);
598
+ }
599
+ }
600
+ }
601
+ return max;
602
+ }
603
+ default:
604
+ throw new Error(`invalid option: ${by}`);
574
605
  }
575
- return v;
576
606
  }
577
607
 
578
608
  maxIndex() {
@@ -591,19 +621,48 @@ export class AbstractMatrix {
591
621
  return idx;
592
622
  }
593
623
 
594
- min() {
624
+ min(by) {
595
625
  if (this.isEmpty()) {
596
626
  return NaN;
597
627
  }
598
- let v = this.get(0, 0);
599
- for (let i = 0; i < this.rows; i++) {
600
- for (let j = 0; j < this.columns; j++) {
601
- if (this.get(i, j) < v) {
602
- v = this.get(i, j);
628
+
629
+ switch (by) {
630
+ case 'row': {
631
+ const min = new Array(this.rows).fill(Number.POSITIVE_INFINITY);
632
+ for (let row = 0; row < this.rows; row++) {
633
+ for (let column = 0; column < this.columns; column++) {
634
+ if (this.get(row, column) < min[row]) {
635
+ min[row] = this.get(row, column);
636
+ }
637
+ }
638
+ }
639
+ return min;
640
+ }
641
+ case 'column': {
642
+ const min = new Array(this.columns).fill(Number.POSITIVE_INFINITY);
643
+ for (let row = 0; row < this.rows; row++) {
644
+ for (let column = 0; column < this.columns; column++) {
645
+ if (this.get(row, column) < min[column]) {
646
+ min[column] = this.get(row, column);
647
+ }
648
+ }
603
649
  }
650
+ return min;
604
651
  }
652
+ case undefined: {
653
+ let min = this.get(0, 0);
654
+ for (let row = 0; row < this.rows; row++) {
655
+ for (let column = 0; column < this.columns; column++) {
656
+ if (this.get(row, column) < min) {
657
+ min = this.get(row, column);
658
+ }
659
+ }
660
+ }
661
+ return min;
662
+ }
663
+ default:
664
+ throw new Error(`invalid option: ${by}`);
605
665
  }
606
- return v;
607
666
  }
608
667
 
609
668
  minIndex() {
@@ -1237,12 +1296,13 @@ export class AbstractMatrix {
1237
1296
  }
1238
1297
 
1239
1298
  selection(rowIndices, columnIndices) {
1240
- let indices = checkIndices(this, rowIndices, columnIndices);
1299
+ checkRowIndices(this, rowIndices);
1300
+ checkColumnIndices(this, columnIndices);
1241
1301
  let newMatrix = new Matrix(rowIndices.length, columnIndices.length);
1242
- for (let i = 0; i < indices.row.length; i++) {
1243
- let rowIndex = indices.row[i];
1244
- for (let j = 0; j < indices.column.length; j++) {
1245
- let columnIndex = indices.column[j];
1302
+ for (let i = 0; i < rowIndices.length; i++) {
1303
+ let rowIndex = rowIndices[i];
1304
+ for (let j = 0; j < columnIndices.length; j++) {
1305
+ let columnIndex = columnIndices[j];
1246
1306
  newMatrix.set(i, j, this.get(rowIndex, columnIndex));
1247
1307
  }
1248
1308
  }
@@ -1330,13 +1390,13 @@ export class AbstractMatrix {
1330
1390
  }
1331
1391
  switch (by) {
1332
1392
  case 'row': {
1333
- if (!Array.isArray(mean)) {
1393
+ if (!isAnyArray(mean)) {
1334
1394
  throw new TypeError('mean must be an array');
1335
1395
  }
1336
1396
  return varianceByRow(this, unbiased, mean);
1337
1397
  }
1338
1398
  case 'column': {
1339
- if (!Array.isArray(mean)) {
1399
+ if (!isAnyArray(mean)) {
1340
1400
  throw new TypeError('mean must be an array');
1341
1401
  }
1342
1402
  return varianceByColumn(this, unbiased, mean);
@@ -1379,14 +1439,14 @@ export class AbstractMatrix {
1379
1439
  const { center = this.mean(by) } = options;
1380
1440
  switch (by) {
1381
1441
  case 'row': {
1382
- if (!Array.isArray(center)) {
1442
+ if (!isAnyArray(center)) {
1383
1443
  throw new TypeError('center must be an array');
1384
1444
  }
1385
1445
  centerByRow(this, center);
1386
1446
  return this;
1387
1447
  }
1388
1448
  case 'column': {
1389
- if (!Array.isArray(center)) {
1449
+ if (!isAnyArray(center)) {
1390
1450
  throw new TypeError('center must be an array');
1391
1451
  }
1392
1452
  centerByColumn(this, center);
@@ -1417,7 +1477,7 @@ export class AbstractMatrix {
1417
1477
  case 'row': {
1418
1478
  if (scale === undefined) {
1419
1479
  scale = getScaleByRow(this);
1420
- } else if (!Array.isArray(scale)) {
1480
+ } else if (!isAnyArray(scale)) {
1421
1481
  throw new TypeError('scale must be an array');
1422
1482
  }
1423
1483
  scaleByRow(this, scale);
@@ -1426,7 +1486,7 @@ export class AbstractMatrix {
1426
1486
  case 'column': {
1427
1487
  if (scale === undefined) {
1428
1488
  scale = getScaleByColumn(this);
1429
- } else if (!Array.isArray(scale)) {
1489
+ } else if (!isAnyArray(scale)) {
1430
1490
  throw new TypeError('scale must be an array');
1431
1491
  }
1432
1492
  scaleByColumn(this, scale);
@@ -1461,6 +1521,12 @@ function compareNumbers(a, b) {
1461
1521
  return a - b;
1462
1522
  }
1463
1523
 
1524
+ function isArrayOfNumbers(array) {
1525
+ return array.every((element) => {
1526
+ return typeof element === 'number';
1527
+ });
1528
+ }
1529
+
1464
1530
  // Synonyms
1465
1531
  AbstractMatrix.random = AbstractMatrix.rand;
1466
1532
  AbstractMatrix.randomInt = AbstractMatrix.randInt;
@@ -1487,7 +1553,7 @@ export default class Matrix extends AbstractMatrix {
1487
1553
  } else {
1488
1554
  throw new TypeError('nColumns must be a positive integer');
1489
1555
  }
1490
- } else if (Array.isArray(nRows)) {
1556
+ } else if (isAnyArray(nRows)) {
1491
1557
  // Copy the values from the 2D array
1492
1558
  const arrayData = nRows;
1493
1559
  nRows = arrayData.length;
@@ -1502,6 +1568,9 @@ export default class Matrix extends AbstractMatrix {
1502
1568
  if (arrayData[i].length !== nColumns) {
1503
1569
  throw new RangeError('Inconsistent array dimensions');
1504
1570
  }
1571
+ if (!isArrayOfNumbers(arrayData[i])) {
1572
+ throw new TypeError('Input data contains non-numeric values');
1573
+ }
1505
1574
  this.data.push(Float64Array.from(arrayData[i]));
1506
1575
  }
1507
1576
  } else {
package/src/util.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { isAnyArray } from 'is-any-array';
2
+
1
3
  /**
2
4
  * @private
3
5
  * Check that a row index is not out of bounds
@@ -64,46 +66,28 @@ export function checkColumnVector(matrix, vector) {
64
66
  return vector;
65
67
  }
66
68
 
67
- export function checkIndices(matrix, rowIndices, columnIndices) {
68
- return {
69
- row: checkRowIndices(matrix, rowIndices),
70
- column: checkColumnIndices(matrix, columnIndices),
71
- };
72
- }
73
-
74
69
  export function checkRowIndices(matrix, rowIndices) {
75
- if (typeof rowIndices !== 'object') {
76
- throw new TypeError('unexpected type for row indices');
70
+ if (!isAnyArray(rowIndices)) {
71
+ throw new TypeError('row indices must be an array');
77
72
  }
78
73
 
79
- let rowOut = rowIndices.some((r) => {
80
- return r < 0 || r >= matrix.rows;
81
- });
82
-
83
- if (rowOut) {
84
- throw new RangeError('row indices are out of range');
74
+ for (let i = 0; i < rowIndices.length; i++) {
75
+ if (rowIndices[i] < 0 || rowIndices[i] >= matrix.rows) {
76
+ throw new RangeError('row indices are out of range');
77
+ }
85
78
  }
86
-
87
- if (!Array.isArray(rowIndices)) rowIndices = Array.from(rowIndices);
88
-
89
- return rowIndices;
90
79
  }
91
80
 
92
81
  export function checkColumnIndices(matrix, columnIndices) {
93
- if (typeof columnIndices !== 'object') {
94
- throw new TypeError('unexpected type for column indices');
82
+ if (!isAnyArray(columnIndices)) {
83
+ throw new TypeError('column indices must be an array');
95
84
  }
96
85
 
97
- let columnOut = columnIndices.some((c) => {
98
- return c < 0 || c >= matrix.columns;
99
- });
100
-
101
- if (columnOut) {
102
- throw new RangeError('column indices are out of range');
86
+ for (let i = 0; i < columnIndices.length; i++) {
87
+ if (columnIndices[i] < 0 || columnIndices[i] >= matrix.columns) {
88
+ throw new RangeError('column indices are out of range');
89
+ }
103
90
  }
104
- if (!Array.isArray(columnIndices)) columnIndices = Array.from(columnIndices);
105
-
106
- return columnIndices;
107
91
  }
108
92
 
109
93
  export function checkRange(matrix, startRow, endRow, startColumn, endColumn) {
@@ -4,7 +4,7 @@ import BaseView from './base';
4
4
 
5
5
  export default class MatrixColumnSelectionView extends BaseView {
6
6
  constructor(matrix, columnIndices) {
7
- columnIndices = checkColumnIndices(matrix, columnIndices);
7
+ checkColumnIndices(matrix, columnIndices);
8
8
  super(matrix, matrix.rows, columnIndices.length);
9
9
  this.columnIndices = columnIndices;
10
10
  }
@@ -4,7 +4,7 @@ import BaseView from './base';
4
4
 
5
5
  export default class MatrixRowSelectionView extends BaseView {
6
6
  constructor(matrix, rowIndices) {
7
- rowIndices = checkRowIndices(matrix, rowIndices);
7
+ checkRowIndices(matrix, rowIndices);
8
8
  super(matrix, rowIndices.length, matrix.columns);
9
9
  this.rowIndices = rowIndices;
10
10
  }
@@ -1,13 +1,14 @@
1
- import { checkIndices } from '../util';
1
+ import { checkRowIndices, checkColumnIndices } from '../util';
2
2
 
3
3
  import BaseView from './base';
4
4
 
5
5
  export default class MatrixSelectionView extends BaseView {
6
6
  constructor(matrix, rowIndices, columnIndices) {
7
- let indices = checkIndices(matrix, rowIndices, columnIndices);
8
- super(matrix, indices.row.length, indices.column.length);
9
- this.rowIndices = indices.row;
10
- this.columnIndices = indices.column;
7
+ checkRowIndices(matrix, rowIndices);
8
+ checkColumnIndices(matrix, columnIndices);
9
+ super(matrix, rowIndices.length, columnIndices.length);
10
+ this.rowIndices = rowIndices;
11
+ this.columnIndices = columnIndices;
11
12
  }
12
13
 
13
14
  set(rowIndex, columnIndex, value) {
package/src/wrap/wrap.js CHANGED
@@ -1,9 +1,11 @@
1
+ import { isAnyArray } from 'is-any-array';
2
+
1
3
  import WrapperMatrix1D from './WrapperMatrix1D';
2
4
  import WrapperMatrix2D from './WrapperMatrix2D';
3
5
 
4
6
  export function wrap(array, options) {
5
- if (Array.isArray(array)) {
6
- if (array[0] && Array.isArray(array[0])) {
7
+ if (isAnyArray(array)) {
8
+ if (array[0] && isAnyArray(array[0])) {
7
9
  return new WrapperMatrix2D(array);
8
10
  } else {
9
11
  return new WrapperMatrix1D(array, options);