catniff 0.1.2 → 0.1.3
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 +2 -2
- package/dist/tensor.d.ts +1 -0
- package/dist/tensor.js +133 -200
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ There is a built-in `TensorMath` class to help with Tensor arithmetic, for examp
|
|
|
31
31
|
const { TensorMath } = require("catniff");
|
|
32
32
|
|
|
33
33
|
const A = [ 1, 2, 3 ];
|
|
34
|
-
const B = 3
|
|
34
|
+
const B = 3;
|
|
35
35
|
console.log(TensorMath.add(A, B));
|
|
36
36
|
```
|
|
37
37
|
|
|
@@ -41,7 +41,7 @@ All available APIs are in `./src/tensor.ts`.
|
|
|
41
41
|
|
|
42
42
|
To compute the gradient of our mathematical expression, we use the `Node` class to dynamically build our DAG:
|
|
43
43
|
```js
|
|
44
|
-
const { Node } = require("
|
|
44
|
+
const { Node } = require("catniff");
|
|
45
45
|
|
|
46
46
|
const X = new Node([
|
|
47
47
|
[ 0.5, -1.0 ],
|
package/dist/tensor.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export type Tensor = number | Tensor[];
|
|
|
2
2
|
export declare class TensorMath {
|
|
3
3
|
static create(num: number, shape: number[]): Tensor;
|
|
4
4
|
static getShape(tA: Tensor): number[];
|
|
5
|
+
static padShape(tA: Tensor, tB: Tensor): [Tensor[], Tensor[]];
|
|
5
6
|
static add(tA: Tensor, tB: Tensor): Tensor;
|
|
6
7
|
static sub(tA: Tensor, tB: Tensor): Tensor;
|
|
7
8
|
static mul(tA: Tensor, tB: Tensor): Tensor;
|
package/dist/tensor.js
CHANGED
|
@@ -22,255 +22,188 @@ class TensorMath {
|
|
|
22
22
|
}
|
|
23
23
|
return shape;
|
|
24
24
|
}
|
|
25
|
+
static padShape(tA, tB) {
|
|
26
|
+
let dimA = TensorMath.getShape(tA).length;
|
|
27
|
+
let dimB = TensorMath.getShape(tB).length;
|
|
28
|
+
while (dimA < dimB) {
|
|
29
|
+
dimA++;
|
|
30
|
+
tA = [tA];
|
|
31
|
+
}
|
|
32
|
+
while (dimA > dimB) {
|
|
33
|
+
dimB++;
|
|
34
|
+
tB = [tB];
|
|
35
|
+
}
|
|
36
|
+
return [tA, tB];
|
|
37
|
+
}
|
|
25
38
|
static add(tA, tB) {
|
|
26
39
|
if (typeof tA === "number" && typeof tB === "number") {
|
|
27
40
|
return tA + tB;
|
|
28
41
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
else if (Array.isArray(tA) && typeof tB === "number") {
|
|
43
|
-
return tA.map(subA => TensorMath.add(subA, tB));
|
|
44
|
-
}
|
|
45
|
-
else if (typeof tA === "number" && Array.isArray(tB)) {
|
|
46
|
-
return tB.map(subB => TensorMath.add(tA, subB));
|
|
47
|
-
}
|
|
48
|
-
throw new Error("Inputs are not tensors");
|
|
42
|
+
[tA, tB] = TensorMath.padShape(tA, tB);
|
|
43
|
+
const outLen = Math.max(tA.length, tB.length);
|
|
44
|
+
if (tA.length !== tB.length && tA.length !== 1 && tB.length !== 1) {
|
|
45
|
+
throw new Error("Inputs are incompatible tensors");
|
|
46
|
+
}
|
|
47
|
+
const result = [];
|
|
48
|
+
for (let i = 0; i < outLen; i++) {
|
|
49
|
+
const subA = tA[tA.length === 1 ? 0 : i];
|
|
50
|
+
const subB = tB[tB.length === 1 ? 0 : i];
|
|
51
|
+
result.push(TensorMath.add(subA, subB));
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
49
54
|
}
|
|
50
55
|
static sub(tA, tB) {
|
|
51
56
|
if (typeof tA === "number" && typeof tB === "number") {
|
|
52
57
|
return tA - tB;
|
|
53
58
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
else if (Array.isArray(tA) && typeof tB === "number") {
|
|
68
|
-
return tA.map(subA => TensorMath.sub(subA, tB));
|
|
69
|
-
}
|
|
70
|
-
else if (typeof tA === "number" && Array.isArray(tB)) {
|
|
71
|
-
return tB.map(subB => TensorMath.sub(tA, subB));
|
|
72
|
-
}
|
|
73
|
-
throw new Error("Inputs are not tensors");
|
|
59
|
+
[tA, tB] = TensorMath.padShape(tA, tB);
|
|
60
|
+
const outLen = Math.max(tA.length, tB.length);
|
|
61
|
+
if (tA.length !== tB.length && tA.length !== 1 && tB.length !== 1) {
|
|
62
|
+
throw new Error("Inputs are incompatible tensors");
|
|
63
|
+
}
|
|
64
|
+
const result = [];
|
|
65
|
+
for (let i = 0; i < outLen; i++) {
|
|
66
|
+
const subA = tA[tA.length === 1 ? 0 : i];
|
|
67
|
+
const subB = tB[tB.length === 1 ? 0 : i];
|
|
68
|
+
result.push(TensorMath.sub(subA, subB));
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
74
71
|
}
|
|
75
72
|
static mul(tA, tB) {
|
|
76
73
|
if (typeof tA === "number" && typeof tB === "number") {
|
|
77
74
|
return tA * tB;
|
|
78
75
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
else if (Array.isArray(tA) && typeof tB === "number") {
|
|
93
|
-
return tA.map(subA => TensorMath.mul(subA, tB));
|
|
94
|
-
}
|
|
95
|
-
else if (typeof tA === "number" && Array.isArray(tB)) {
|
|
96
|
-
return tB.map(subB => TensorMath.mul(tA, subB));
|
|
97
|
-
}
|
|
98
|
-
throw new Error("Inputs are not tensors");
|
|
76
|
+
[tA, tB] = TensorMath.padShape(tA, tB);
|
|
77
|
+
const outLen = Math.max(tA.length, tB.length);
|
|
78
|
+
if (tA.length !== tB.length && tA.length !== 1 && tB.length !== 1) {
|
|
79
|
+
throw new Error("Inputs are incompatible tensors");
|
|
80
|
+
}
|
|
81
|
+
const result = [];
|
|
82
|
+
for (let i = 0; i < outLen; i++) {
|
|
83
|
+
const subA = tA[tA.length === 1 ? 0 : i];
|
|
84
|
+
const subB = tB[tB.length === 1 ? 0 : i];
|
|
85
|
+
result.push(TensorMath.mul(subA, subB));
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
99
88
|
}
|
|
100
89
|
static pow(tA, tB) {
|
|
101
90
|
if (typeof tA === "number" && typeof tB === "number") {
|
|
102
91
|
return tA ** tB;
|
|
103
92
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
else if (Array.isArray(tA) && typeof tB === "number") {
|
|
118
|
-
return tA.map(subA => TensorMath.pow(subA, tB));
|
|
119
|
-
}
|
|
120
|
-
else if (typeof tA === "number" && Array.isArray(tB)) {
|
|
121
|
-
return tB.map(subB => TensorMath.pow(tA, subB));
|
|
122
|
-
}
|
|
123
|
-
throw new Error("Inputs are not tensors");
|
|
93
|
+
[tA, tB] = TensorMath.padShape(tA, tB);
|
|
94
|
+
const outLen = Math.max(tA.length, tB.length);
|
|
95
|
+
if (tA.length !== tB.length && tA.length !== 1 && tB.length !== 1) {
|
|
96
|
+
throw new Error("Inputs are incompatible tensors");
|
|
97
|
+
}
|
|
98
|
+
const result = [];
|
|
99
|
+
for (let i = 0; i < outLen; i++) {
|
|
100
|
+
const subA = tA[tA.length === 1 ? 0 : i];
|
|
101
|
+
const subB = tB[tB.length === 1 ? 0 : i];
|
|
102
|
+
result.push(TensorMath.pow(subA, subB));
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
124
105
|
}
|
|
125
106
|
static div(tA, tB) {
|
|
126
107
|
if (typeof tA === "number" && typeof tB === "number") {
|
|
127
108
|
return tA / tB;
|
|
128
109
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
else if (Array.isArray(tA) && typeof tB === "number") {
|
|
143
|
-
return tA.map(subA => TensorMath.div(subA, tB));
|
|
144
|
-
}
|
|
145
|
-
else if (typeof tA === "number" && Array.isArray(tB)) {
|
|
146
|
-
return tB.map(subB => TensorMath.div(tA, subB));
|
|
147
|
-
}
|
|
148
|
-
throw new Error("Inputs are not tensors");
|
|
110
|
+
[tA, tB] = TensorMath.padShape(tA, tB);
|
|
111
|
+
const outLen = Math.max(tA.length, tB.length);
|
|
112
|
+
if (tA.length !== tB.length && tA.length !== 1 && tB.length !== 1) {
|
|
113
|
+
throw new Error("Inputs are incompatible tensors");
|
|
114
|
+
}
|
|
115
|
+
const result = [];
|
|
116
|
+
for (let i = 0; i < outLen; i++) {
|
|
117
|
+
const subA = tA[tA.length === 1 ? 0 : i];
|
|
118
|
+
const subB = tB[tB.length === 1 ? 0 : i];
|
|
119
|
+
result.push(TensorMath.div(subA, subB));
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
149
122
|
}
|
|
150
123
|
static gt(tA, tB) {
|
|
151
124
|
if (typeof tA === "number" && typeof tB === "number") {
|
|
152
125
|
return tA > tB ? 1 : 0;
|
|
153
126
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
else if (Array.isArray(tA) && typeof tB === "number") {
|
|
168
|
-
return tA.map(subA => TensorMath.gt(subA, tB));
|
|
169
|
-
}
|
|
170
|
-
else if (typeof tA === "number" && Array.isArray(tB)) {
|
|
171
|
-
return tB.map(subB => TensorMath.gt(tA, subB));
|
|
172
|
-
}
|
|
173
|
-
throw new Error("Inputs are not tensors");
|
|
127
|
+
[tA, tB] = TensorMath.padShape(tA, tB);
|
|
128
|
+
const outLen = Math.max(tA.length, tB.length);
|
|
129
|
+
if (tA.length !== tB.length && tA.length !== 1 && tB.length !== 1) {
|
|
130
|
+
throw new Error("Inputs are incompatible tensors");
|
|
131
|
+
}
|
|
132
|
+
const result = [];
|
|
133
|
+
for (let i = 0; i < outLen; i++) {
|
|
134
|
+
const subA = tA[tA.length === 1 ? 0 : i];
|
|
135
|
+
const subB = tB[tB.length === 1 ? 0 : i];
|
|
136
|
+
result.push(TensorMath.gt(subA, subB));
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
174
139
|
}
|
|
175
140
|
static lt(tA, tB) {
|
|
176
141
|
if (typeof tA === "number" && typeof tB === "number") {
|
|
177
142
|
return tA < tB ? 1 : 0;
|
|
178
143
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
else if (Array.isArray(tA) && typeof tB === "number") {
|
|
193
|
-
return tA.map(subA => TensorMath.lt(subA, tB));
|
|
194
|
-
}
|
|
195
|
-
else if (typeof tA === "number" && Array.isArray(tB)) {
|
|
196
|
-
return tB.map(subB => TensorMath.lt(tA, subB));
|
|
197
|
-
}
|
|
198
|
-
throw new Error("Inputs are not tensors");
|
|
144
|
+
[tA, tB] = TensorMath.padShape(tA, tB);
|
|
145
|
+
const outLen = Math.max(tA.length, tB.length);
|
|
146
|
+
if (tA.length !== tB.length && tA.length !== 1 && tB.length !== 1) {
|
|
147
|
+
throw new Error("Inputs are incompatible tensors");
|
|
148
|
+
}
|
|
149
|
+
const result = [];
|
|
150
|
+
for (let i = 0; i < outLen; i++) {
|
|
151
|
+
const subA = tA[tA.length === 1 ? 0 : i];
|
|
152
|
+
const subB = tB[tB.length === 1 ? 0 : i];
|
|
153
|
+
result.push(TensorMath.lt(subA, subB));
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
199
156
|
}
|
|
200
157
|
static ge(tA, tB) {
|
|
201
158
|
if (typeof tA === "number" && typeof tB === "number") {
|
|
202
159
|
return tA >= tB ? 1 : 0;
|
|
203
160
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
else if (Array.isArray(tA) && typeof tB === "number") {
|
|
218
|
-
return tA.map(subA => TensorMath.ge(subA, tB));
|
|
219
|
-
}
|
|
220
|
-
else if (typeof tA === "number" && Array.isArray(tB)) {
|
|
221
|
-
return tB.map(subB => TensorMath.ge(tA, subB));
|
|
222
|
-
}
|
|
223
|
-
throw new Error("Inputs are not tensors");
|
|
161
|
+
[tA, tB] = TensorMath.padShape(tA, tB);
|
|
162
|
+
const outLen = Math.max(tA.length, tB.length);
|
|
163
|
+
if (tA.length !== tB.length && tA.length !== 1 && tB.length !== 1) {
|
|
164
|
+
throw new Error("Inputs are incompatible tensors");
|
|
165
|
+
}
|
|
166
|
+
const result = [];
|
|
167
|
+
for (let i = 0; i < outLen; i++) {
|
|
168
|
+
const subA = tA[tA.length === 1 ? 0 : i];
|
|
169
|
+
const subB = tB[tB.length === 1 ? 0 : i];
|
|
170
|
+
result.push(TensorMath.ge(subA, subB));
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
224
173
|
}
|
|
225
174
|
static le(tA, tB) {
|
|
226
175
|
if (typeof tA === "number" && typeof tB === "number") {
|
|
227
176
|
return tA <= tB ? 1 : 0;
|
|
228
177
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
else if (Array.isArray(tA) && typeof tB === "number") {
|
|
243
|
-
return tA.map(subA => TensorMath.le(subA, tB));
|
|
244
|
-
}
|
|
245
|
-
else if (typeof tA === "number" && Array.isArray(tB)) {
|
|
246
|
-
return tB.map(subB => TensorMath.le(tA, subB));
|
|
247
|
-
}
|
|
248
|
-
throw new Error("Inputs are not tensors");
|
|
178
|
+
[tA, tB] = TensorMath.padShape(tA, tB);
|
|
179
|
+
const outLen = Math.max(tA.length, tB.length);
|
|
180
|
+
if (tA.length !== tB.length && tA.length !== 1 && tB.length !== 1) {
|
|
181
|
+
throw new Error("Inputs are incompatible tensors");
|
|
182
|
+
}
|
|
183
|
+
const result = [];
|
|
184
|
+
for (let i = 0; i < outLen; i++) {
|
|
185
|
+
const subA = tA[tA.length === 1 ? 0 : i];
|
|
186
|
+
const subB = tB[tB.length === 1 ? 0 : i];
|
|
187
|
+
result.push(TensorMath.le(subA, subB));
|
|
188
|
+
}
|
|
189
|
+
return result;
|
|
249
190
|
}
|
|
250
191
|
static eq(tA, tB) {
|
|
251
192
|
if (typeof tA === "number" && typeof tB === "number") {
|
|
252
193
|
return tA === tB ? 1 : 0;
|
|
253
194
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
else if (Array.isArray(tA) && typeof tB === "number") {
|
|
268
|
-
return tA.map(subA => TensorMath.eq(subA, tB));
|
|
269
|
-
}
|
|
270
|
-
else if (typeof tA === "number" && Array.isArray(tB)) {
|
|
271
|
-
return tB.map(subB => TensorMath.eq(tA, subB));
|
|
272
|
-
}
|
|
273
|
-
throw new Error("Inputs are not tensors");
|
|
195
|
+
[tA, tB] = TensorMath.padShape(tA, tB);
|
|
196
|
+
const outLen = Math.max(tA.length, tB.length);
|
|
197
|
+
if (tA.length !== tB.length && tA.length !== 1 && tB.length !== 1) {
|
|
198
|
+
throw new Error("Inputs are incompatible tensors");
|
|
199
|
+
}
|
|
200
|
+
const result = [];
|
|
201
|
+
for (let i = 0; i < outLen; i++) {
|
|
202
|
+
const subA = tA[tA.length === 1 ? 0 : i];
|
|
203
|
+
const subB = tB[tB.length === 1 ? 0 : i];
|
|
204
|
+
result.push(TensorMath.eq(subA, subB));
|
|
205
|
+
}
|
|
206
|
+
return result;
|
|
274
207
|
}
|
|
275
208
|
static neg(tA) {
|
|
276
209
|
if (typeof tA === "number") {
|