@smockle/matrix 4.0.0 → 4.0.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/.github/workflows/publish.yml +1 -0
- package/.github/workflows/test.yml +1 -0
- package/dist/__tests__/index.test.d.ts +1 -0
- package/dist/__tests__/index.test.js +355 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +230 -0
- package/package.json +1 -1
- package/src/index.ts +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import { inspect } from "node:util";
|
|
2
|
+
import { describe, test, expect } from "@jest/globals";
|
|
3
|
+
import Matrix from "../index.js";
|
|
4
|
+
describe("Matrix", () => {
|
|
5
|
+
const error = new TypeError("Matrix must be a number or array of numbers");
|
|
6
|
+
test("instanceof Matrix", () => {
|
|
7
|
+
expect(Matrix([])).toBeInstanceOf(Matrix);
|
|
8
|
+
});
|
|
9
|
+
test("throws unnecessary nesting", () => {
|
|
10
|
+
expect(Matrix.bind(Matrix, [[1, 2]])).toThrowError(error);
|
|
11
|
+
});
|
|
12
|
+
test("throws uneven rows", () => {
|
|
13
|
+
expect(Matrix.bind(Matrix, [[1, 2], [3], [4, 5]])).toThrowError(error);
|
|
14
|
+
});
|
|
15
|
+
test("does not throw number", () => {
|
|
16
|
+
expect(Matrix.bind(Matrix, 1)).not.toThrowError(error);
|
|
17
|
+
});
|
|
18
|
+
test("does not throw number array", () => {
|
|
19
|
+
expect(Matrix.bind(Matrix, [1])).not.toThrowError(error);
|
|
20
|
+
});
|
|
21
|
+
test("does not throw 2D number array", () => {
|
|
22
|
+
expect(Matrix.bind(Matrix, [[1], [2]])).not.toThrowError(error);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe("Matrix.addable", () => {
|
|
26
|
+
test("addable mismatched columns", () => {
|
|
27
|
+
expect(Matrix.addable(Matrix([
|
|
28
|
+
[1, 2],
|
|
29
|
+
[3, 4],
|
|
30
|
+
]), Matrix([
|
|
31
|
+
[1, 2, 3],
|
|
32
|
+
[4, 5, 6],
|
|
33
|
+
]))).toBeFalsy();
|
|
34
|
+
});
|
|
35
|
+
test("addable mismatched rows", () => {
|
|
36
|
+
expect(Matrix.addable(Matrix([
|
|
37
|
+
[1, 2],
|
|
38
|
+
[3, 4],
|
|
39
|
+
]), Matrix([
|
|
40
|
+
[1, 2],
|
|
41
|
+
[4, 5],
|
|
42
|
+
[7, 8],
|
|
43
|
+
]))).toBeFalsy();
|
|
44
|
+
});
|
|
45
|
+
test("addable", () => {
|
|
46
|
+
expect(Matrix.addable(Matrix([
|
|
47
|
+
[1, 2],
|
|
48
|
+
[3, 4],
|
|
49
|
+
]), Matrix([
|
|
50
|
+
[5, 6],
|
|
51
|
+
[7, 8],
|
|
52
|
+
]))).toBeTruthy();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe("Matrix#addable", () => {
|
|
56
|
+
test("addable mismatched columns", () => {
|
|
57
|
+
expect(Matrix([
|
|
58
|
+
[1, 2],
|
|
59
|
+
[3, 4],
|
|
60
|
+
]).addable(Matrix([
|
|
61
|
+
[1, 2, 3],
|
|
62
|
+
[4, 5, 6],
|
|
63
|
+
]))).toBeFalsy();
|
|
64
|
+
});
|
|
65
|
+
test("addable mismatched rows", () => {
|
|
66
|
+
expect(Matrix([
|
|
67
|
+
[1, 2],
|
|
68
|
+
[3, 4],
|
|
69
|
+
]).addable(Matrix([
|
|
70
|
+
[1, 2],
|
|
71
|
+
[4, 5],
|
|
72
|
+
[7, 8],
|
|
73
|
+
]))).toBeFalsy();
|
|
74
|
+
});
|
|
75
|
+
test("addable", () => {
|
|
76
|
+
expect(Matrix([
|
|
77
|
+
[1, 2],
|
|
78
|
+
[3, 4],
|
|
79
|
+
]).addable(Matrix([
|
|
80
|
+
[5, 6],
|
|
81
|
+
[7, 8],
|
|
82
|
+
]))).toBeTruthy();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe("Matrix.add", () => {
|
|
86
|
+
test("add throws typerror", () => {
|
|
87
|
+
expect(Matrix.add.bind(Matrix, Matrix([
|
|
88
|
+
[1, 2],
|
|
89
|
+
[3, 4],
|
|
90
|
+
]), Matrix([
|
|
91
|
+
[1, 2, 3],
|
|
92
|
+
[4, 5, 6],
|
|
93
|
+
]))).toThrowError(new TypeError("Matrices are not addable"));
|
|
94
|
+
});
|
|
95
|
+
test("add", () => {
|
|
96
|
+
expect(Matrix.add(Matrix([
|
|
97
|
+
[1, 2],
|
|
98
|
+
[3, 4],
|
|
99
|
+
]), Matrix([
|
|
100
|
+
[5, 6],
|
|
101
|
+
[7, 8],
|
|
102
|
+
]))).toStrictEqual(Matrix([
|
|
103
|
+
[6, 8],
|
|
104
|
+
[10, 12],
|
|
105
|
+
]));
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
describe("Matrix#add", () => {
|
|
109
|
+
const addmatrix = Matrix([
|
|
110
|
+
[1, 2],
|
|
111
|
+
[3, 4],
|
|
112
|
+
]);
|
|
113
|
+
test("add throws typerror", () => {
|
|
114
|
+
expect(addmatrix.add.bind(addmatrix, Matrix([
|
|
115
|
+
[1, 2, 3],
|
|
116
|
+
[4, 5, 6],
|
|
117
|
+
]))).toThrowError(new TypeError("Matrices are not addable"));
|
|
118
|
+
});
|
|
119
|
+
test("add", () => {
|
|
120
|
+
expect(Matrix([
|
|
121
|
+
[1, 2],
|
|
122
|
+
[3, 4],
|
|
123
|
+
]).add(Matrix([
|
|
124
|
+
[5, 6],
|
|
125
|
+
[7, 8],
|
|
126
|
+
]))).toStrictEqual(Matrix([
|
|
127
|
+
[6, 8],
|
|
128
|
+
[10, 12],
|
|
129
|
+
]));
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
describe("Matrix.multipliable", () => {
|
|
133
|
+
test("multipliable mismatched columns and rows", () => {
|
|
134
|
+
expect(Matrix.multipliable(Matrix([
|
|
135
|
+
[1, 2, 3],
|
|
136
|
+
[4, 5, 6],
|
|
137
|
+
]), Matrix([
|
|
138
|
+
[1, 2],
|
|
139
|
+
[4, 5],
|
|
140
|
+
]))).toBeFalsy();
|
|
141
|
+
});
|
|
142
|
+
test("multipliable", () => {
|
|
143
|
+
expect(Matrix.multipliable(Matrix([
|
|
144
|
+
[1, 2],
|
|
145
|
+
[3, 4],
|
|
146
|
+
]), Matrix([
|
|
147
|
+
[5, 6],
|
|
148
|
+
[7, 8],
|
|
149
|
+
]))).toBeTruthy();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
describe("Matrix#multipliable", () => {
|
|
153
|
+
test("multipliable mismatched columns and rows", () => {
|
|
154
|
+
expect(Matrix([
|
|
155
|
+
[1, 2, 3],
|
|
156
|
+
[4, 5, 6],
|
|
157
|
+
]).multipliable(Matrix([
|
|
158
|
+
[1, 2],
|
|
159
|
+
[4, 5],
|
|
160
|
+
]))).toBeFalsy();
|
|
161
|
+
});
|
|
162
|
+
test("multipliable", () => {
|
|
163
|
+
expect(Matrix([
|
|
164
|
+
[1, 2],
|
|
165
|
+
[3, 4],
|
|
166
|
+
]).multipliable(Matrix([
|
|
167
|
+
[5, 6],
|
|
168
|
+
[7, 8],
|
|
169
|
+
]))).toBeTruthy();
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
describe("Matrix.multiply", () => {
|
|
173
|
+
const multiplymatrix = Matrix([1, 2, 3]);
|
|
174
|
+
test("multiply throws typerror", () => {
|
|
175
|
+
expect(multiplymatrix.multiply.bind(multiplymatrix, Matrix([
|
|
176
|
+
[1, 2],
|
|
177
|
+
[3, 4],
|
|
178
|
+
]))).toThrowError(new TypeError("Matrices are not multipliable"));
|
|
179
|
+
});
|
|
180
|
+
test("multiply number", () => {
|
|
181
|
+
expect(Matrix(3).multiply(Matrix(6))).toStrictEqual(Matrix(18));
|
|
182
|
+
});
|
|
183
|
+
test("multiply A (1x2) and B (2x1)", () => {
|
|
184
|
+
expect(Matrix([1, 2]).multiply(Matrix([[3], [4]]))).toStrictEqual(Matrix([11]));
|
|
185
|
+
});
|
|
186
|
+
test("multiply A (2x2) and B (2x2)", () => {
|
|
187
|
+
expect(Matrix([
|
|
188
|
+
[1, 2],
|
|
189
|
+
[3, 4],
|
|
190
|
+
]).multiply(Matrix([
|
|
191
|
+
[5, 6],
|
|
192
|
+
[7, 8],
|
|
193
|
+
]))).toStrictEqual(Matrix([
|
|
194
|
+
[19, 22],
|
|
195
|
+
[43, 50],
|
|
196
|
+
]));
|
|
197
|
+
});
|
|
198
|
+
test("multiply A (2x3) and B (3x2)", () => {
|
|
199
|
+
expect(Matrix([
|
|
200
|
+
[1, 9, 7],
|
|
201
|
+
[8, 1, 2],
|
|
202
|
+
]).multiply(Matrix([
|
|
203
|
+
[3, 2, 1, 5],
|
|
204
|
+
[5, 4, 7, 3],
|
|
205
|
+
[6, 9, 6, 8],
|
|
206
|
+
]))).toStrictEqual(Matrix([
|
|
207
|
+
[90, 101, 106, 88],
|
|
208
|
+
[41, 38, 27, 59],
|
|
209
|
+
]));
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
describe("Matrix#multiply", () => {
|
|
213
|
+
test("multiply throws typerror", () => {
|
|
214
|
+
expect(Matrix.multiply.bind(Matrix, Matrix([1, 2, 3]), Matrix([
|
|
215
|
+
[1, 2],
|
|
216
|
+
[3, 4],
|
|
217
|
+
]))).toThrowError(new TypeError("Matrices are not multipliable"));
|
|
218
|
+
});
|
|
219
|
+
test("multiply number", () => {
|
|
220
|
+
expect(Matrix.multiply(Matrix(3), Matrix(6))).toStrictEqual(Matrix(18));
|
|
221
|
+
});
|
|
222
|
+
test("multiply A (1x2) and B (2x1)", () => {
|
|
223
|
+
expect(Matrix.multiply(Matrix([1, 2]), Matrix([[3], [4]]))).toStrictEqual(Matrix([11]));
|
|
224
|
+
});
|
|
225
|
+
test("multiply A (2x2) and B (2x2)", () => {
|
|
226
|
+
expect(Matrix.multiply(Matrix([
|
|
227
|
+
[1, 2],
|
|
228
|
+
[3, 4],
|
|
229
|
+
]), Matrix([
|
|
230
|
+
[5, 6],
|
|
231
|
+
[7, 8],
|
|
232
|
+
]))).toStrictEqual(Matrix([
|
|
233
|
+
[19, 22],
|
|
234
|
+
[43, 50],
|
|
235
|
+
]));
|
|
236
|
+
});
|
|
237
|
+
test("multiply A (2x3) and B (3x2)", () => {
|
|
238
|
+
expect(Matrix.multiply(Matrix([
|
|
239
|
+
[1, 9, 7],
|
|
240
|
+
[8, 1, 2],
|
|
241
|
+
]), Matrix([
|
|
242
|
+
[3, 2, 1, 5],
|
|
243
|
+
[5, 4, 7, 3],
|
|
244
|
+
[6, 9, 6, 8],
|
|
245
|
+
]))).toStrictEqual(Matrix([
|
|
246
|
+
[90, 101, 106, 88],
|
|
247
|
+
[41, 38, 27, 59],
|
|
248
|
+
]));
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
describe("Matrix#valueOf", () => {
|
|
252
|
+
const array = [3];
|
|
253
|
+
test("valueOf Matrix", () => {
|
|
254
|
+
expect(Matrix(array).valueOf()).toBe(array);
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
describe("Matrix#countRows", () => {
|
|
258
|
+
test("countRows number", () => {
|
|
259
|
+
expect(Matrix(1).countRows()).toBe(0);
|
|
260
|
+
});
|
|
261
|
+
test("countRows number array", () => {
|
|
262
|
+
expect(Matrix([1]).countRows()).toBe(1);
|
|
263
|
+
});
|
|
264
|
+
test("countRows 2D number array", () => {
|
|
265
|
+
expect(Matrix([
|
|
266
|
+
[1, 2],
|
|
267
|
+
[3, 4],
|
|
268
|
+
[5, 6],
|
|
269
|
+
]).countRows()).toBe(3);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
describe("Matrix#countColumns", () => {
|
|
273
|
+
test("countColumns number", () => {
|
|
274
|
+
expect(Matrix(1).countColumns()).toBe(0);
|
|
275
|
+
});
|
|
276
|
+
test("countColumns number array", () => {
|
|
277
|
+
expect(Matrix([1]).countColumns()).toBe(1);
|
|
278
|
+
});
|
|
279
|
+
test("countColumns 2D number array", () => {
|
|
280
|
+
expect(Matrix([[1], [2]]).countColumns()).toBe(1);
|
|
281
|
+
});
|
|
282
|
+
test("countColumns many 2D number array", () => {
|
|
283
|
+
expect(Matrix([
|
|
284
|
+
[1, 2],
|
|
285
|
+
[3, 4],
|
|
286
|
+
[5, 6],
|
|
287
|
+
]).countColumns()).toBe(2);
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
describe("Matrix#transpose", () => {
|
|
291
|
+
test("transpose number", () => {
|
|
292
|
+
expect(Matrix(1).transpose()).toStrictEqual(Matrix(1));
|
|
293
|
+
});
|
|
294
|
+
test("transpose number array", () => {
|
|
295
|
+
expect(Matrix([1, 2]).transpose()).toStrictEqual(Matrix([[1], [2]]));
|
|
296
|
+
});
|
|
297
|
+
test("transpose 2D number array", () => {
|
|
298
|
+
expect(Matrix([
|
|
299
|
+
[1, 2, 3],
|
|
300
|
+
[4, 5, 6],
|
|
301
|
+
]).transpose()).toStrictEqual(Matrix([
|
|
302
|
+
[1, 4],
|
|
303
|
+
[2, 5],
|
|
304
|
+
[3, 6],
|
|
305
|
+
]));
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
describe("Matrix#invert", () => {
|
|
309
|
+
test("invert 2D number array", () => {
|
|
310
|
+
expect(Matrix([
|
|
311
|
+
[1, 2],
|
|
312
|
+
[3, 4],
|
|
313
|
+
]).invert()).toStrictEqual(Matrix([
|
|
314
|
+
[-2, 1],
|
|
315
|
+
[1.5, -0.5],
|
|
316
|
+
]));
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
describe("Matrix#map", () => {
|
|
320
|
+
const matrix = Matrix([1, 2, 3]);
|
|
321
|
+
test("map returns a matrix", () => {
|
|
322
|
+
expect(matrix.map((x) => x + 1)).toBeInstanceOf(Matrix);
|
|
323
|
+
});
|
|
324
|
+
test("map identity", () => {
|
|
325
|
+
expect(matrix.map((x) => x)).toStrictEqual(matrix);
|
|
326
|
+
});
|
|
327
|
+
test("map increment", () => {
|
|
328
|
+
expect(matrix.map((x) => x + 1)).toStrictEqual(Matrix([2, 3, 4]));
|
|
329
|
+
});
|
|
330
|
+
test("map non-mutable", () => {
|
|
331
|
+
expect(matrix).toStrictEqual(Matrix([1, 2, 3]));
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
describe("Matrix#inspect", () => {
|
|
335
|
+
test("inspect number", () => {
|
|
336
|
+
expect(inspect(Matrix(3))).toBe("3");
|
|
337
|
+
});
|
|
338
|
+
test("inspect number array", () => {
|
|
339
|
+
expect(inspect(Matrix([1, 2, 3]))).toBe("[ 1 2 3 ]");
|
|
340
|
+
});
|
|
341
|
+
test("inspect 2D number array", () => {
|
|
342
|
+
expect(inspect(Matrix([
|
|
343
|
+
[1, 2, 3],
|
|
344
|
+
[4, 5, 6],
|
|
345
|
+
[7, 8, 9],
|
|
346
|
+
]))).toBe("[ 1 2 3 ]\n[ 4 5 6 ]\n[ 7 8 9 ]");
|
|
347
|
+
});
|
|
348
|
+
test("inspect padded 2D number array", () => {
|
|
349
|
+
expect(inspect(Matrix([
|
|
350
|
+
[1, 2, 3],
|
|
351
|
+
[-10, 11, -12],
|
|
352
|
+
[100, 0, 0],
|
|
353
|
+
]))).toBe("[ 1 2 3 ]\n[ -10 11 -12 ]\n[ 100 0 0 ]");
|
|
354
|
+
});
|
|
355
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type Matrix = {
|
|
2
|
+
__value: number | (number | number[])[];
|
|
3
|
+
countRows: () => number;
|
|
4
|
+
countColumns: () => number;
|
|
5
|
+
addable: (y: Matrix) => boolean;
|
|
6
|
+
add: (y: Matrix) => Matrix;
|
|
7
|
+
multipliable: (y: Matrix) => boolean;
|
|
8
|
+
multiply: (y: Matrix) => Matrix;
|
|
9
|
+
transpose: () => Matrix;
|
|
10
|
+
invert: () => Matrix;
|
|
11
|
+
map: (x: any) => Matrix;
|
|
12
|
+
valueOf: () => number | (number | number[])[];
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Creates a Matrix
|
|
16
|
+
* @constructor
|
|
17
|
+
* @alias module:matrix
|
|
18
|
+
* @param {number|(number | number[])[]} x - Values to store in matrix
|
|
19
|
+
* @throws {TypeError} Argument x must be a number or number array
|
|
20
|
+
* @return {Matrix} Single or multi dimensional matrix
|
|
21
|
+
*/
|
|
22
|
+
declare function Matrix(x: number | (number | number[])[]): Matrix;
|
|
23
|
+
declare namespace Matrix {
|
|
24
|
+
var addable: (x: Matrix, y: Matrix) => boolean;
|
|
25
|
+
var add: (x: Matrix, y: Matrix) => Matrix;
|
|
26
|
+
var multipliable: (x: Matrix, y: Matrix) => boolean;
|
|
27
|
+
var multiply: (x: Matrix, y: Matrix) => Matrix;
|
|
28
|
+
var invert: (x: Matrix) => Matrix;
|
|
29
|
+
}
|
|
30
|
+
export default Matrix;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { fill, padStart, unzip } from "lodash";
|
|
2
|
+
import { inv } from "mathjs";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a Matrix
|
|
5
|
+
* @constructor
|
|
6
|
+
* @alias module:matrix
|
|
7
|
+
* @param {number|(number | number[])[]} x - Values to store in matrix
|
|
8
|
+
* @throws {TypeError} Argument x must be a number or number array
|
|
9
|
+
* @return {Matrix} Single or multi dimensional matrix
|
|
10
|
+
*/
|
|
11
|
+
function Matrix(x) {
|
|
12
|
+
// extra nesting
|
|
13
|
+
if (Array.isArray(x) && Array.isArray(x[0]) && x.length === 1) {
|
|
14
|
+
throw new TypeError("Matrix must be a number or array of numbers");
|
|
15
|
+
}
|
|
16
|
+
// uneven rows
|
|
17
|
+
if (Array.isArray(x) &&
|
|
18
|
+
Array.isArray(x[0]) &&
|
|
19
|
+
x.some((row) => Array.isArray(row) && row.length !== x[0].length)) {
|
|
20
|
+
throw new TypeError("Matrix must be a number or array of numbers");
|
|
21
|
+
}
|
|
22
|
+
/* Single or multi dimensional matrix */
|
|
23
|
+
const matrix = Object.create(Matrix.prototype);
|
|
24
|
+
matrix.__value = x;
|
|
25
|
+
return matrix;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Determines whether two matrices can be summed
|
|
29
|
+
* @alias module:matrix.addable
|
|
30
|
+
* @param {Matrix} x - Matrix to check
|
|
31
|
+
* @param {Matrix} y - Matrix to check
|
|
32
|
+
* @return {boolean} Whether two matrices can be summed (using matrix addition)
|
|
33
|
+
*/
|
|
34
|
+
Matrix.addable = function (x, y) {
|
|
35
|
+
return (x.countRows() === y.countRows() && x.countColumns() === y.countColumns());
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Adds two matrices using matrix addition
|
|
39
|
+
* @alias module:matrix.add
|
|
40
|
+
* @param {Matrix} x - Matrix to add
|
|
41
|
+
* @param {Matrix} y - Matrix to add
|
|
42
|
+
* @throws {TypeError} Matrices are not addable
|
|
43
|
+
* @return {Matrix} New matrix with the summation
|
|
44
|
+
*/
|
|
45
|
+
Matrix.add = function (x, y) {
|
|
46
|
+
if (!Matrix.addable(x, y))
|
|
47
|
+
throw new TypeError("Matrices are not addable");
|
|
48
|
+
return x.map((row, i) => row.map((column, j) => column + y.__value[i][j]));
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Determines whether two matrices can be multiplied
|
|
52
|
+
* @alias module:matrix.multipliable
|
|
53
|
+
* @param {Matrix} x - Matrix to check
|
|
54
|
+
* @param {Matrix} y - Matrix to check
|
|
55
|
+
* @return {boolean} Whether two matrices can be summed (using matrix multiplication)
|
|
56
|
+
*/
|
|
57
|
+
Matrix.multipliable = function (x, y) {
|
|
58
|
+
return x.countColumns() === y.countRows();
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Calculates the inner product of two matrices
|
|
62
|
+
* @param {Matrix} x - Matrix to multiply
|
|
63
|
+
* @param {Matrix} y - Matrix to multiply
|
|
64
|
+
* @param {number} i - Column in matrix y to multiply
|
|
65
|
+
* @return {number} Inner product of matrices
|
|
66
|
+
*/
|
|
67
|
+
function innerproduct(x, y, i) {
|
|
68
|
+
const _x = x.__value;
|
|
69
|
+
const _y = Array.isArray(unzip(y.__value)) &&
|
|
70
|
+
unzip(y.__value).length === 0
|
|
71
|
+
? unzip([y.__value])[i]
|
|
72
|
+
: unzip(y.__value)[i];
|
|
73
|
+
return []
|
|
74
|
+
.concat(_x)
|
|
75
|
+
.reduce((z, _z, j) => z + _z * _y[j], 0);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Calculates the dot product of two matrices
|
|
79
|
+
* @alias module:matrix.multiply
|
|
80
|
+
* @param {Matrix} x - Matrix to multiply
|
|
81
|
+
* @param {Matrix} y - Matrix to multiply
|
|
82
|
+
* @return {Matrix} New matrix with the dot product
|
|
83
|
+
*/
|
|
84
|
+
Matrix.multiply = function (x, y) {
|
|
85
|
+
if (!Matrix.multipliable(x, y)) {
|
|
86
|
+
throw new TypeError("Matrices are not multipliable");
|
|
87
|
+
}
|
|
88
|
+
if (x.countColumns() === 0 && y.countRows() === 0) {
|
|
89
|
+
return Matrix(x.__value * y.__value);
|
|
90
|
+
}
|
|
91
|
+
/* New matrix with the dot product */
|
|
92
|
+
const z = Matrix(fill(Array(x.countRows()), x.countRows() !== 1 ? fill(Array(y.countColumns()), 0) : 0));
|
|
93
|
+
return z.map((_z, i) => {
|
|
94
|
+
if (typeof _z === "number")
|
|
95
|
+
return innerproduct(x, y, i);
|
|
96
|
+
return _z.map((_, j) => innerproduct(Matrix(x.__value[i]), y, j));
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Inverts a matrix
|
|
101
|
+
* @alias module:matrix.invert
|
|
102
|
+
* @param {x} Matrix to invert
|
|
103
|
+
* @return {Matrix} Matrix inverse
|
|
104
|
+
*/
|
|
105
|
+
Matrix.invert = function (x) {
|
|
106
|
+
return Matrix(inv(x instanceof Matrix ? x.__value : x));
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Counts rows in this matrix
|
|
110
|
+
* @alias module:matrix#countRows
|
|
111
|
+
* @return {number} Number of rows
|
|
112
|
+
*/
|
|
113
|
+
Matrix.prototype.countRows = function () {
|
|
114
|
+
if (typeof this.__value === "number")
|
|
115
|
+
return 0;
|
|
116
|
+
if (typeof this.__value[0] === "number")
|
|
117
|
+
return 1;
|
|
118
|
+
return this.__value.length;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Counts columns in this matrix
|
|
122
|
+
* @alias module:matrix#countColumns
|
|
123
|
+
* @return {number} Number of columns
|
|
124
|
+
*/
|
|
125
|
+
Matrix.prototype.countColumns = function () {
|
|
126
|
+
if (typeof this.__value === "number")
|
|
127
|
+
return 0;
|
|
128
|
+
if (typeof this.__value[0] === "number")
|
|
129
|
+
return this.__value.length;
|
|
130
|
+
return this.__value[0].length;
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Determines whether this matrix can be summed
|
|
134
|
+
* @alias module:matrix#addable
|
|
135
|
+
* @param {Matrix} y - Matrix to check
|
|
136
|
+
* @return {boolean} Whether this matrix can be summed (using matrix addition)
|
|
137
|
+
*/
|
|
138
|
+
Matrix.prototype.addable = function (y) {
|
|
139
|
+
return Matrix.addable(this, y);
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Adds this matrix using matrix addition
|
|
143
|
+
* @alias module:matrix#add
|
|
144
|
+
* @param {Matrix} y - Matrix to add
|
|
145
|
+
* @return {Matrix} New matrix with the summation
|
|
146
|
+
*/
|
|
147
|
+
Matrix.prototype.add = function (y) {
|
|
148
|
+
return Matrix.add(this, y);
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Determines whether this matrix can be multiplied
|
|
152
|
+
* @alias module:matrix#multipliable
|
|
153
|
+
* @param {Matrix} y - Matrix to check
|
|
154
|
+
* @return {boolean} Whether two matrices can be summed (using matrix multiplication)
|
|
155
|
+
*/
|
|
156
|
+
Matrix.prototype.multipliable = function (y) {
|
|
157
|
+
return Matrix.multipliable(this, y);
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Calculates the dot product of this matrix
|
|
161
|
+
* @alias module:matrix#multiply
|
|
162
|
+
* @param {Matrix} y - Matrix to multiply
|
|
163
|
+
* @return {Matrix} New matrix with the dot product
|
|
164
|
+
*/
|
|
165
|
+
Matrix.prototype.multiply = function (y) {
|
|
166
|
+
return Matrix.multiply(this, y);
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Calculates the transpose of this matrix
|
|
170
|
+
* @alias module:matrix#transpose
|
|
171
|
+
* @return {Matrix} New matrix with the transpose
|
|
172
|
+
*/
|
|
173
|
+
Matrix.prototype.transpose = function () {
|
|
174
|
+
switch (this.countRows()) {
|
|
175
|
+
case 0:
|
|
176
|
+
return Matrix(this.__value);
|
|
177
|
+
case 1:
|
|
178
|
+
return Matrix(unzip([this.__value]));
|
|
179
|
+
default:
|
|
180
|
+
return Matrix(unzip(this.__value));
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* Inverts this matrix
|
|
185
|
+
* @alias module:matrix#invert
|
|
186
|
+
* @return {Matrix} Matrix inverse
|
|
187
|
+
*/
|
|
188
|
+
Matrix.prototype.invert = function () {
|
|
189
|
+
return Matrix.invert(this);
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* Maps over this matrix
|
|
193
|
+
* @alias module:matrix#map
|
|
194
|
+
* @return {Matrix} Matrix inverse
|
|
195
|
+
*/
|
|
196
|
+
Matrix.prototype.map = function (x) {
|
|
197
|
+
if (typeof this.__value === "number")
|
|
198
|
+
return Matrix(x(this.__value));
|
|
199
|
+
return Matrix(this.__value.map(x));
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* Returns the number or number array value
|
|
203
|
+
* @alias module:matrix#valueOf
|
|
204
|
+
* @return {number|number[]} Number of number array value
|
|
205
|
+
*/
|
|
206
|
+
Matrix.prototype.valueOf = function () {
|
|
207
|
+
return this.__value;
|
|
208
|
+
};
|
|
209
|
+
/**
|
|
210
|
+
* Formats and prints the matrix value
|
|
211
|
+
* @alias module:matrix#inspect
|
|
212
|
+
* @return {string} Formatted matrix value
|
|
213
|
+
*/
|
|
214
|
+
Matrix.prototype[Symbol.for("nodejs.util.inspect.custom")] = function () {
|
|
215
|
+
switch (this.countRows()) {
|
|
216
|
+
case 0:
|
|
217
|
+
return `${this.__value}`;
|
|
218
|
+
case 1:
|
|
219
|
+
return `[ ${this.__value.join(" ")} ]`;
|
|
220
|
+
default:
|
|
221
|
+
/* Output array filled with zeroes */
|
|
222
|
+
const padding = unzip(this.__value).map((column) => column.reduce((length, x) => Math.max(`${x}`.length, length), 0));
|
|
223
|
+
return this.__value
|
|
224
|
+
.reduce((output, row) => `${output}[ ${row
|
|
225
|
+
.map((x, i) => padStart(`${x}`, padding[i]))
|
|
226
|
+
.join(" ")} ]`, "")
|
|
227
|
+
.replace(/]\[/g, "]\n[");
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
export default Matrix;
|
package/package.json
CHANGED
package/src/index.ts
CHANGED