matrix-lite 0.1.0
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 +272 -0
- package/package.json +39 -0
- package/src/index.js +178 -0
package/README.md
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# matrix-lite
|
|
2
|
+
|
|
3
|
+
**matrixlite** is a tiny, dependency-free JavaScript library for basic matrix operations.
|
|
4
|
+
It is designed to be simple, explicit, and predictable, without TypeScript, classes, or hidden magic.
|
|
5
|
+
|
|
6
|
+
Matrices are represented as plain 2D arrays (`number[][]`).
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
* Works in Node.js (CommonJS & ESM compatible)
|
|
11
|
+
* Simple and explicit API
|
|
12
|
+
* Predictable data structures (plain arrays)
|
|
13
|
+
* Safe shape validation with clear errors
|
|
14
|
+
* Floating-point comparison with epsilon support
|
|
15
|
+
|
|
16
|
+
### Supported operations:
|
|
17
|
+
|
|
18
|
+
* Matrix creation (zeros, identity)
|
|
19
|
+
* Shape inspection (shape)
|
|
20
|
+
* Matrix arithmetic (add, sub, scale, mul)
|
|
21
|
+
* Transformations (transpose)
|
|
22
|
+
* Vector math (dot, row, col)
|
|
23
|
+
* Utilities (clone, map, eq)
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install matrixlite
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Importing
|
|
32
|
+
|
|
33
|
+
### CommonJS (Node.js)
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
const M = require('matrixlite');
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### ES Modules
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
import * as M from 'matrixlite';
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Matrix Representation
|
|
46
|
+
|
|
47
|
+
A matrix is a rectangular 2D array of numbers:
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
const A = [
|
|
51
|
+
[1, 2, 3],
|
|
52
|
+
[4, 5, 6]
|
|
53
|
+
];
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Rules
|
|
57
|
+
|
|
58
|
+
* All rows must have the same length
|
|
59
|
+
* Matrices must be non-empty
|
|
60
|
+
* All values should be numbers
|
|
61
|
+
|
|
62
|
+
## API Reference
|
|
63
|
+
|
|
64
|
+
`shape(matrix)`
|
|
65
|
+
|
|
66
|
+
Returns matrix dimensions as `[rows, cols]`.
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
M.shape([[1, 2], [3, 4]]);
|
|
70
|
+
// → [2, 2]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Throws if the matrix is invalid or ragged.
|
|
74
|
+
|
|
75
|
+
`zeros(rows, cols)`
|
|
76
|
+
|
|
77
|
+
Creates a matrix filled with zeros.
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
M.zeros(2, 3);
|
|
81
|
+
// [
|
|
82
|
+
// [0, 0, 0],
|
|
83
|
+
// [0, 0, 0]
|
|
84
|
+
// ]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`identity(n)`
|
|
88
|
+
|
|
89
|
+
Creates an `n × n` identity matrix.
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
M.identity(3);
|
|
93
|
+
// [
|
|
94
|
+
// [1, 0, 0],
|
|
95
|
+
// [0, 1, 0],
|
|
96
|
+
// [0, 0, 1]
|
|
97
|
+
// ]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`clone(matrix)`
|
|
101
|
+
|
|
102
|
+
Returns a deep copy of a matrix.
|
|
103
|
+
|
|
104
|
+
```js
|
|
105
|
+
const B = M.clone(A);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`map(matrix, fn)`
|
|
109
|
+
|
|
110
|
+
Applies a function to each element.
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
M.map(A, v => v * 2);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Callback signature:
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
(value, rowIndex, colIndex) => number
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`add(A, B)`
|
|
123
|
+
|
|
124
|
+
Element-wise matrix addition.
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
M.add([[1, 2]], [[3, 4]]);
|
|
128
|
+
// [[4, 6]]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Matrices must have the same shape.
|
|
132
|
+
|
|
133
|
+
`sub(A, B)`
|
|
134
|
+
|
|
135
|
+
Element-wise subtraction.
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
M.sub([[5, 5]], [[2, 3]]);
|
|
139
|
+
// [[3, 2]]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`scale(matrix, k)`
|
|
143
|
+
|
|
144
|
+
Multiplies every element by a scalar.
|
|
145
|
+
|
|
146
|
+
```js
|
|
147
|
+
M.scale([[1, 2]], 10);
|
|
148
|
+
// [[10, 20]]
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`transpose(matrix)`
|
|
152
|
+
|
|
153
|
+
Transposes a matrix.
|
|
154
|
+
|
|
155
|
+
```js
|
|
156
|
+
M.transpose([
|
|
157
|
+
[1, 2, 3],
|
|
158
|
+
[4, 5, 6]
|
|
159
|
+
]);
|
|
160
|
+
// [
|
|
161
|
+
// [1, 4],
|
|
162
|
+
// [2, 5],
|
|
163
|
+
// [3, 6]
|
|
164
|
+
// ]
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`mul(A, B)`
|
|
168
|
+
|
|
169
|
+
Matrix multiplication (`A × B`).
|
|
170
|
+
|
|
171
|
+
```js
|
|
172
|
+
const A = [
|
|
173
|
+
[1, 2, 3],
|
|
174
|
+
[4, 5, 6]
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
const B = [
|
|
178
|
+
[7, 8],
|
|
179
|
+
[9, 10],
|
|
180
|
+
[11, 12]
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
M.mul(A, B);
|
|
184
|
+
// [
|
|
185
|
+
// [58, 64],
|
|
186
|
+
// [139, 154]
|
|
187
|
+
// ]
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Rules:
|
|
191
|
+
|
|
192
|
+
* `A.cols === B.rows`
|
|
193
|
+
* Uses classic O(n³) multiplication
|
|
194
|
+
* Optimized loop order for cache friendliness
|
|
195
|
+
|
|
196
|
+
`dot(a, b)`
|
|
197
|
+
|
|
198
|
+
Dot product of two vectors.
|
|
199
|
+
|
|
200
|
+
```js
|
|
201
|
+
M.dot([1, 2, 3], [4, 5, 6]);
|
|
202
|
+
// 32
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Vectors must have equal length.
|
|
206
|
+
|
|
207
|
+
`row(matrix, index)`
|
|
208
|
+
|
|
209
|
+
Returns a copy of a matrix row.
|
|
210
|
+
|
|
211
|
+
```js
|
|
212
|
+
M.row(A, 0);
|
|
213
|
+
// [1, 2, 3]
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`col(matrix, index)`
|
|
217
|
+
|
|
218
|
+
Returns a column as a vector.
|
|
219
|
+
|
|
220
|
+
```js
|
|
221
|
+
M.col(A, 1);
|
|
222
|
+
// [2, 5]
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
`eq(A, B, eps = 0)`
|
|
226
|
+
|
|
227
|
+
Checks matrix equality with optional tolerance.
|
|
228
|
+
|
|
229
|
+
```js
|
|
230
|
+
M.eq([[1, 1.001]], [[1, 1.002]], 0.01);
|
|
231
|
+
// true
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Useful for floating-point comparisons.
|
|
235
|
+
|
|
236
|
+
## Error Handling
|
|
237
|
+
|
|
238
|
+
All functions:
|
|
239
|
+
|
|
240
|
+
* Validate matrix shape
|
|
241
|
+
* Throw meaningful TypeError or RangeError
|
|
242
|
+
* Never silently fix invalid input
|
|
243
|
+
|
|
244
|
+
Example:
|
|
245
|
+
```js
|
|
246
|
+
M.add([[1, 2]], [[1]]);
|
|
247
|
+
// RangeError: shape mismatch
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Performance Notes
|
|
251
|
+
|
|
252
|
+
* Intended for small to medium matrices
|
|
253
|
+
* Not optimized for large-scale numerical computing
|
|
254
|
+
* No SIMD, WASM, or GPU acceleration
|
|
255
|
+
* Perfect for:
|
|
256
|
+
* Education
|
|
257
|
+
* Prototyping
|
|
258
|
+
* Small math utilities
|
|
259
|
+
* Backend logic
|
|
260
|
+
|
|
261
|
+
What This Library Is NOT
|
|
262
|
+
|
|
263
|
+
* ❌ A NumPy replacement
|
|
264
|
+
* ❌ A linear algebra research toolkit
|
|
265
|
+
* ❌ A GPU-accelerated math engine
|
|
266
|
+
* ❌ A TypeScript-heavy framework
|
|
267
|
+
|
|
268
|
+
This is a minimalist utility library.
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
## License
|
|
272
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "matrix-lite",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Simple matrix utilities (JS only)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"matrix",
|
|
7
|
+
"math",
|
|
8
|
+
"linear-algebra"
|
|
9
|
+
],
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"author": "",
|
|
12
|
+
"main": "./src/index.js",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"require": "./src/index.js",
|
|
16
|
+
"import": "./src/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"type": "commonjs",
|
|
20
|
+
"files": [
|
|
21
|
+
"src",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"test": "node test/basic.test.js"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"bignumber.js": "^9.3.1",
|
|
30
|
+
"fast-math": "^1.0.2",
|
|
31
|
+
"fraction.js": "^5.3.4",
|
|
32
|
+
"gl-matrix": "^3.4.4",
|
|
33
|
+
"micro-math": "^0.10.0",
|
|
34
|
+
"ml-matrix": "^6.12.1",
|
|
35
|
+
"numeric": "^1.2.6",
|
|
36
|
+
"simple-statistics": "^7.8.8",
|
|
37
|
+
"tinyparrot": "^0.0.18"
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Matrix is represented as Array<Array<number>> (rows).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
function isMatrix(A) {
|
|
8
|
+
return Array.isArray(A) && A.length > 0 && A.every(r => Array.isArray(r) && r.length > 0);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function shape(A) {
|
|
12
|
+
if (!isMatrix(A)) throw new TypeError('Expected a non-empty 2D array');
|
|
13
|
+
const rows = A.length;
|
|
14
|
+
const cols = A[0].length;
|
|
15
|
+
for (let i = 1; i < rows; i++) {
|
|
16
|
+
if (A[i].length !== cols) throw new TypeError('Ragged matrix (rows have different lengths)');
|
|
17
|
+
}
|
|
18
|
+
return [rows, cols];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function clone(A) {
|
|
22
|
+
shape(A);
|
|
23
|
+
return A.map(r => r.slice());
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function zeros(rows, cols) {
|
|
27
|
+
if (!Number.isInteger(rows) || !Number.isInteger(cols) || rows <= 0 || cols <= 0) {
|
|
28
|
+
throw new TypeError('rows/cols must be positive integers');
|
|
29
|
+
}
|
|
30
|
+
const out = new Array(rows);
|
|
31
|
+
for (let i = 0; i < rows; i++) {
|
|
32
|
+
const row = new Array(cols);
|
|
33
|
+
for (let j = 0; j < cols; j++) row[j] = 0;
|
|
34
|
+
out[i] = row;
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function identity(n) {
|
|
40
|
+
if (!Number.isInteger(n) || n <= 0) throw new TypeError('n must be a positive integer');
|
|
41
|
+
const I = zeros(n, n);
|
|
42
|
+
for (let i = 0; i < n; i++) I[i][i] = 1;
|
|
43
|
+
return I;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function map(A, fn) {
|
|
47
|
+
const [r, c] = shape(A);
|
|
48
|
+
const out = new Array(r);
|
|
49
|
+
for (let i = 0; i < r; i++) {
|
|
50
|
+
const row = new Array(c);
|
|
51
|
+
for (let j = 0; j < c; j++) row[j] = fn(A[i][j], i, j);
|
|
52
|
+
out[i] = row;
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function add(A, B) {
|
|
58
|
+
const [ar, ac] = shape(A);
|
|
59
|
+
const [br, bc] = shape(B);
|
|
60
|
+
if (ar !== br || ac !== bc) throw new RangeError('add: shape mismatch');
|
|
61
|
+
const out = new Array(ar);
|
|
62
|
+
for (let i = 0; i < ar; i++) {
|
|
63
|
+
const row = new Array(ac);
|
|
64
|
+
for (let j = 0; j < ac; j++) row[j] = A[i][j] + B[i][j];
|
|
65
|
+
out[i] = row;
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function sub(A, B) {
|
|
71
|
+
const [ar, ac] = shape(A);
|
|
72
|
+
const [br, bc] = shape(B);
|
|
73
|
+
if (ar !== br || ac !== bc) throw new RangeError('sub: shape mismatch');
|
|
74
|
+
const out = new Array(ar);
|
|
75
|
+
for (let i = 0; i < ar; i++) {
|
|
76
|
+
const row = new Array(ac);
|
|
77
|
+
for (let j = 0; j < ac; j++) row[j] = A[i][j] - B[i][j];
|
|
78
|
+
out[i] = row;
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function scale(A, k) {
|
|
84
|
+
if (typeof k !== 'number' || !Number.isFinite(k)) throw new TypeError('k must be a finite number');
|
|
85
|
+
return map(A, v => v * k);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function transpose(A) {
|
|
89
|
+
const [r, c] = shape(A);
|
|
90
|
+
const out = new Array(c);
|
|
91
|
+
for (let j = 0; j < c; j++) {
|
|
92
|
+
const row = new Array(r);
|
|
93
|
+
for (let i = 0; i < r; i++) row[i] = A[i][j];
|
|
94
|
+
out[j] = row;
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function mul(A, B) {
|
|
100
|
+
const [ar, ac] = shape(A);
|
|
101
|
+
const [br, bc] = shape(B);
|
|
102
|
+
if (ac !== br) throw new RangeError('mul: shape mismatch (A cols must equal B rows)');
|
|
103
|
+
const out = zeros(ar, bc);
|
|
104
|
+
|
|
105
|
+
// classic O(n^3) with a cache-friendly loop order
|
|
106
|
+
for (let i = 0; i < ar; i++) {
|
|
107
|
+
const Ai = A[i];
|
|
108
|
+
const outi = out[i];
|
|
109
|
+
for (let k = 0; k < ac; k++) {
|
|
110
|
+
const aik = Ai[k];
|
|
111
|
+
const Bk = B[k];
|
|
112
|
+
for (let j = 0; j < bc; j++) {
|
|
113
|
+
outi[j] += aik * Bk[j];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function dot(a, b) {
|
|
121
|
+
if (!Array.isArray(a) || !Array.isArray(b) || a.length === 0 || b.length === 0) {
|
|
122
|
+
throw new TypeError('dot: expected non-empty arrays');
|
|
123
|
+
}
|
|
124
|
+
if (a.length !== b.length) throw new RangeError('dot: length mismatch');
|
|
125
|
+
let s = 0;
|
|
126
|
+
for (let i = 0; i < a.length; i++) s += a[i] * b[i];
|
|
127
|
+
return s;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function row(A, i) {
|
|
131
|
+
const [r] = shape(A);
|
|
132
|
+
if (!Number.isInteger(i) || i < 0 || i >= r) throw new RangeError('row: index out of range');
|
|
133
|
+
return A[i].slice();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function col(A, j) {
|
|
137
|
+
const [r, c] = shape(A);
|
|
138
|
+
if (!Number.isInteger(j) || j < 0 || j >= c) throw new RangeError('col: index out of range');
|
|
139
|
+
const out = new Array(r);
|
|
140
|
+
for (let i = 0; i < r; i++) out[i] = A[i][j];
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function eq(A, B, eps = 0) {
|
|
145
|
+
const [ar, ac] = shape(A);
|
|
146
|
+
const [br, bc] = shape(B);
|
|
147
|
+
if (ar !== br || ac !== bc) return false;
|
|
148
|
+
if (typeof eps !== 'number' || eps < 0) throw new TypeError('eps must be a non-negative number');
|
|
149
|
+
for (let i = 0; i < ar; i++) {
|
|
150
|
+
for (let j = 0; j < ac; j++) {
|
|
151
|
+
const d = Math.abs(A[i][j] - B[i][j]);
|
|
152
|
+
if (d > eps) return false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
module.exports = {
|
|
159
|
+
// constructors
|
|
160
|
+
zeros,
|
|
161
|
+
identity,
|
|
162
|
+
|
|
163
|
+
// validators / helpers
|
|
164
|
+
shape,
|
|
165
|
+
clone,
|
|
166
|
+
map,
|
|
167
|
+
row,
|
|
168
|
+
col,
|
|
169
|
+
eq,
|
|
170
|
+
|
|
171
|
+
// ops
|
|
172
|
+
add,
|
|
173
|
+
sub,
|
|
174
|
+
scale,
|
|
175
|
+
transpose,
|
|
176
|
+
mul,
|
|
177
|
+
dot
|
|
178
|
+
};
|