@danielsimonjr/mathts-tensor 0.2.27 → 0.3.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/dist/Tensor.d.ts +8 -3
- package/dist/Tensor.d.ts.map +1 -1
- package/dist/index.js +161 -78
- package/package.json +3 -3
package/dist/Tensor.d.ts
CHANGED
|
@@ -61,10 +61,17 @@ export declare class Tensor {
|
|
|
61
61
|
*/
|
|
62
62
|
toDenseMatrix(): DenseMatrix;
|
|
63
63
|
private sameShape;
|
|
64
|
-
private elementwise;
|
|
65
64
|
add(other: Tensor | number): Tensor;
|
|
66
65
|
sub(other: Tensor | number): Tensor;
|
|
67
66
|
mul(other: Tensor | number): Tensor;
|
|
67
|
+
/** Element-wise division; broadcasts like `mul`. Division by zero follows IEEE-754. */
|
|
68
|
+
div(other: Tensor | number): Tensor;
|
|
69
|
+
/** Element-wise negation. */
|
|
70
|
+
neg(): Tensor;
|
|
71
|
+
/** Apply `f` to every element, returning a new tensor of the same shape (labels preserved). */
|
|
72
|
+
map(f: (x: number, index: number) => number): Tensor;
|
|
73
|
+
/** Deep copy: independent data buffer; shape and axisLabels are carried over. */
|
|
74
|
+
clone(): Tensor;
|
|
68
75
|
scale(k: number): Tensor;
|
|
69
76
|
normInf(): number;
|
|
70
77
|
/**
|
|
@@ -159,8 +166,6 @@ export declare class Tensor {
|
|
|
159
166
|
* `undefined` ⇒ all axes (reduce everything to a rank-0 scalar).
|
|
160
167
|
*/
|
|
161
168
|
private resolveAxes;
|
|
162
|
-
private static forEachIndex;
|
|
163
|
-
private static flatIndex;
|
|
164
169
|
reshape(shape: ReadonlyArray<number>): Tensor;
|
|
165
170
|
transpose(perm?: ReadonlyArray<number>): Tensor;
|
|
166
171
|
matMul(other: Tensor): Tensor;
|
package/dist/Tensor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tensor.d.ts","sourceRoot":"","sources":["../src/Tensor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,WAAW,EAAkB,MAAM,8BAA8B,CAAC;AAC3E,OAAO,KAAK,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAC1F,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;AAElD;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC;QACnC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;KAChF,CAAC,CAAC;IACH,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnF;AAED;;;;;GAKG;AACH,qBAAa,MAAM;IACjB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,8FAA8F;IAC9F,QAAQ,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAE3C,YAAY,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,EAgB9F;IAED,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAElD;IAED,8FAA8F;IAC9F,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAE7D;IAED,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAoBzE;IAED,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAIjC;IAED,QAAQ,IAAI,WAAW,CAgBtB;IAED;;;OAGG;IACH,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"Tensor.d.ts","sourceRoot":"","sources":["../src/Tensor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -56,51 +56,91 @@ var Tensor = class Tensor {
|
|
|
56
56
|
return build(0, 0);
|
|
57
57
|
}
|
|
58
58
|
static fromDenseMatrix(m) {
|
|
59
|
-
|
|
60
|
-
const rows = nested.length;
|
|
61
|
-
const cols = rows > 0 ? nested[0].length : 0;
|
|
62
|
-
return Tensor.fromNested(nested, [rows, cols]);
|
|
59
|
+
return new Tensor([m.rows, m.cols], m.toFloat64Array());
|
|
63
60
|
}
|
|
64
61
|
toDenseMatrix() {
|
|
65
62
|
if (this.shape.length !== 2) throw new Error(`Tensor.toDenseMatrix: expected a rank-2 tensor, got rank ${this.shape.length}`);
|
|
66
|
-
return DenseMatrix
|
|
63
|
+
return new DenseMatrix(this.shape[0], this.shape[1], this.data.slice());
|
|
67
64
|
}
|
|
68
65
|
sameShape(other) {
|
|
69
66
|
return this.shape.length === other.shape.length && this.shape.every((v, i) => v === other.shape[i]);
|
|
70
67
|
}
|
|
71
|
-
elementwise(other, op, f) {
|
|
72
|
-
if (!this.sameShape(other)) throw new Error(`Tensor.${op}: shape mismatch [${this.shape}] vs [${other.shape}]`);
|
|
73
|
-
const out = new Float64Array(this.data.length);
|
|
74
|
-
for (let i = 0; i < this.data.length; i++) out[i] = f(this.data[i], other.data[i]);
|
|
75
|
-
return new Tensor(this.shape, out);
|
|
76
|
-
}
|
|
77
68
|
add(other) {
|
|
69
|
+
const a = this.data;
|
|
78
70
|
if (typeof other === "number") {
|
|
79
|
-
const out = new Float64Array(
|
|
80
|
-
for (let i = 0; i <
|
|
71
|
+
const out = new Float64Array(a.length);
|
|
72
|
+
for (let i = 0; i < a.length; i++) out[i] = a[i] + other;
|
|
73
|
+
return new Tensor(this.shape, out, this.axisLabels);
|
|
74
|
+
}
|
|
75
|
+
if (this.sameShape(other)) {
|
|
76
|
+
const b = other.data;
|
|
77
|
+
const out = new Float64Array(a.length);
|
|
78
|
+
for (let i = 0; i < a.length; i++) out[i] = a[i] + b[i];
|
|
81
79
|
return new Tensor(this.shape, out, this.axisLabels);
|
|
82
80
|
}
|
|
83
|
-
if (this.sameShape(other)) return this.elementwise(other, "add", (x, y) => x + y);
|
|
84
81
|
return Tensor.broadcastOp(this, other, "add", (x, y) => x + y);
|
|
85
82
|
}
|
|
86
83
|
sub(other) {
|
|
84
|
+
const a = this.data;
|
|
87
85
|
if (typeof other === "number") {
|
|
88
|
-
const out = new Float64Array(
|
|
89
|
-
for (let i = 0; i <
|
|
86
|
+
const out = new Float64Array(a.length);
|
|
87
|
+
for (let i = 0; i < a.length; i++) out[i] = a[i] - other;
|
|
88
|
+
return new Tensor(this.shape, out, this.axisLabels);
|
|
89
|
+
}
|
|
90
|
+
if (this.sameShape(other)) {
|
|
91
|
+
const b = other.data;
|
|
92
|
+
const out = new Float64Array(a.length);
|
|
93
|
+
for (let i = 0; i < a.length; i++) out[i] = a[i] - b[i];
|
|
90
94
|
return new Tensor(this.shape, out, this.axisLabels);
|
|
91
95
|
}
|
|
92
|
-
if (this.sameShape(other)) return this.elementwise(other, "sub", (x, y) => x - y);
|
|
93
96
|
return Tensor.broadcastOp(this, other, "sub", (x, y) => x - y);
|
|
94
97
|
}
|
|
95
98
|
mul(other) {
|
|
96
99
|
if (typeof other === "number") return this.scale(other);
|
|
97
|
-
|
|
100
|
+
const a = this.data;
|
|
101
|
+
if (this.sameShape(other)) {
|
|
102
|
+
const b = other.data;
|
|
103
|
+
const out = new Float64Array(a.length);
|
|
104
|
+
for (let i = 0; i < a.length; i++) out[i] = a[i] * b[i];
|
|
105
|
+
return new Tensor(this.shape, out, this.axisLabels);
|
|
106
|
+
}
|
|
98
107
|
return Tensor.broadcastOp(this, other, "mul", (x, y) => x * y);
|
|
99
108
|
}
|
|
109
|
+
div(other) {
|
|
110
|
+
const a = this.data;
|
|
111
|
+
if (typeof other === "number") {
|
|
112
|
+
const out = new Float64Array(a.length);
|
|
113
|
+
for (let i = 0; i < a.length; i++) out[i] = a[i] / other;
|
|
114
|
+
return new Tensor(this.shape, out, this.axisLabels);
|
|
115
|
+
}
|
|
116
|
+
if (this.sameShape(other)) {
|
|
117
|
+
const b = other.data;
|
|
118
|
+
const out = new Float64Array(a.length);
|
|
119
|
+
for (let i = 0; i < a.length; i++) out[i] = a[i] / b[i];
|
|
120
|
+
return new Tensor(this.shape, out, this.axisLabels);
|
|
121
|
+
}
|
|
122
|
+
return Tensor.broadcastOp(this, other, "div", (x, y) => x / y);
|
|
123
|
+
}
|
|
124
|
+
neg() {
|
|
125
|
+
const a = this.data;
|
|
126
|
+
const out = new Float64Array(a.length);
|
|
127
|
+
for (let i = 0; i < a.length; i++) out[i] = -a[i];
|
|
128
|
+
return new Tensor(this.shape, out, this.axisLabels);
|
|
129
|
+
}
|
|
130
|
+
map(f) {
|
|
131
|
+
const a = this.data;
|
|
132
|
+
const out = new Float64Array(a.length);
|
|
133
|
+
for (let i = 0; i < a.length; i++) out[i] = f(a[i], i);
|
|
134
|
+
return new Tensor(this.shape, out, this.axisLabels);
|
|
135
|
+
}
|
|
136
|
+
clone() {
|
|
137
|
+
return new Tensor([...this.shape], this.data.slice(), this.axisLabels);
|
|
138
|
+
}
|
|
100
139
|
scale(k) {
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
140
|
+
const a = this.data;
|
|
141
|
+
const out = new Float64Array(a.length);
|
|
142
|
+
for (let i = 0; i < a.length; i++) out[i] = a[i] * k;
|
|
143
|
+
return new Tensor(this.shape, out, this.axisLabels);
|
|
104
144
|
}
|
|
105
145
|
normInf() {
|
|
106
146
|
let max = 0;
|
|
@@ -162,6 +202,7 @@ var Tensor = class Tensor {
|
|
|
162
202
|
const rank = this.shape.length;
|
|
163
203
|
const axisSet = new Set(axes);
|
|
164
204
|
for (const ax of axes) if (!Number.isInteger(ax) || ax < 0 || ax >= rank) throw new Error(`Tensor.reduce: axis ${ax} out of range for rank-${rank} tensor`);
|
|
205
|
+
if (axisSet.size !== axes.length) throw new Error(`Tensor.reduce: duplicate axes in [${axes}]`);
|
|
165
206
|
const outShape = [];
|
|
166
207
|
for (let k = 0; k < rank; k++) if (axisSet.has(k)) {
|
|
167
208
|
if (keepDims) outShape.push(1);
|
|
@@ -170,20 +211,28 @@ var Tensor = class Tensor {
|
|
|
170
211
|
const outSize = Tensor.sizeOf(outShape);
|
|
171
212
|
const out = new Float64Array(outSize).fill(init);
|
|
172
213
|
const outStrides = Tensor.rowMajorStrides(outShape.length > 0 ? outShape : [1]);
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
for (let n = 0; n < inSize; n++) {
|
|
176
|
-
let outFlat = 0;
|
|
214
|
+
const contrib = new Array(rank).fill(0);
|
|
215
|
+
{
|
|
177
216
|
let outDim = 0;
|
|
178
217
|
for (let k = 0; k < rank; k++) if (axisSet.has(k)) {
|
|
179
218
|
if (keepDims) outDim++;
|
|
180
219
|
} else {
|
|
181
|
-
|
|
220
|
+
contrib[k] = outStrides[outDim];
|
|
182
221
|
outDim++;
|
|
183
222
|
}
|
|
184
|
-
|
|
223
|
+
}
|
|
224
|
+
const inCoords = new Array(rank).fill(0);
|
|
225
|
+
const inSize = this.data.length;
|
|
226
|
+
const data = this.data;
|
|
227
|
+
let outFlat = 0;
|
|
228
|
+
for (let n = 0; n < inSize; n++) {
|
|
229
|
+
out[outFlat] = combine(out[outFlat], data[n]);
|
|
185
230
|
for (let k = rank - 1; k >= 0; k--) {
|
|
186
|
-
if (++inCoords[k] < this.shape[k])
|
|
231
|
+
if (++inCoords[k] < this.shape[k]) {
|
|
232
|
+
outFlat += contrib[k];
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
outFlat -= contrib[k] * (this.shape[k] - 1);
|
|
187
236
|
inCoords[k] = 0;
|
|
188
237
|
}
|
|
189
238
|
}
|
|
@@ -285,26 +334,6 @@ var Tensor = class Tensor {
|
|
|
285
334
|
if (typeof axis === "number") return [axis];
|
|
286
335
|
return [...axis];
|
|
287
336
|
}
|
|
288
|
-
static forEachIndex(shape, visit) {
|
|
289
|
-
if (shape.length === 0) {
|
|
290
|
-
visit([]);
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
const idx = new Array(shape.length).fill(0);
|
|
294
|
-
const total = Tensor.sizeOf(shape);
|
|
295
|
-
for (let n = 0; n < total; n++) {
|
|
296
|
-
visit(idx);
|
|
297
|
-
for (let k = shape.length - 1; k >= 0; k--) {
|
|
298
|
-
if (++idx[k] < shape[k]) break;
|
|
299
|
-
idx[k] = 0;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
static flatIndex(idx, strides) {
|
|
304
|
-
let f = 0;
|
|
305
|
-
for (let k = 0; k < idx.length; k++) f += idx[k] * strides[k];
|
|
306
|
-
return f;
|
|
307
|
-
}
|
|
308
337
|
reshape(shape) {
|
|
309
338
|
if (Tensor.sizeOf(shape) !== this.data.length) throw new Error(`Tensor.reshape: size mismatch [${this.shape}] -> [${shape}]`);
|
|
310
339
|
return new Tensor([...shape], this.data.slice());
|
|
@@ -313,15 +342,31 @@ var Tensor = class Tensor {
|
|
|
313
342
|
const rank = this.shape.length;
|
|
314
343
|
const p = perm ?? Array.from({ length: rank }, (_, i) => rank - 1 - i);
|
|
315
344
|
if (p.length !== rank) throw new Error(`Tensor.transpose: perm length ${p.length} != rank ${rank}`);
|
|
345
|
+
const seen = new Array(rank).fill(false);
|
|
346
|
+
for (const axis of p) {
|
|
347
|
+
if (!Number.isInteger(axis) || axis < 0 || axis >= rank) throw new Error(`Tensor.transpose: perm axis ${axis} out of range for rank-${rank} tensor`);
|
|
348
|
+
if (seen[axis]) throw new Error(`Tensor.transpose: perm [${p}] is not a permutation (repeated axis ${axis})`);
|
|
349
|
+
seen[axis] = true;
|
|
350
|
+
}
|
|
316
351
|
const outShape = p.map((axis) => this.shape[axis]);
|
|
317
352
|
const inStrides = Tensor.rowMajorStrides(this.shape);
|
|
318
|
-
const
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
353
|
+
const permStrides = p.map((axis) => inStrides[axis]);
|
|
354
|
+
const src = this.data;
|
|
355
|
+
const total = src.length;
|
|
356
|
+
const out = new Float64Array(total);
|
|
357
|
+
const coords = new Array(rank).fill(0);
|
|
358
|
+
let inOff = 0;
|
|
359
|
+
for (let n = 0; n < total; n++) {
|
|
360
|
+
out[n] = src[inOff];
|
|
361
|
+
for (let k = rank - 1; k >= 0; k--) {
|
|
362
|
+
if (++coords[k] < outShape[k]) {
|
|
363
|
+
inOff += permStrides[k];
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
inOff -= permStrides[k] * (outShape[k] - 1);
|
|
367
|
+
coords[k] = 0;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
325
370
|
return new Tensor(outShape, out);
|
|
326
371
|
}
|
|
327
372
|
matMul(other) {
|
|
@@ -333,18 +378,31 @@ var Tensor = class Tensor {
|
|
|
333
378
|
return new Tensor([m, n], c.toFloat64Array());
|
|
334
379
|
}
|
|
335
380
|
static einsum(spec, ...operands) {
|
|
381
|
+
const nOps = operands.length;
|
|
382
|
+
const seenRefs = /* @__PURE__ */ new Set();
|
|
383
|
+
const checkRef = (what, operand, axis) => {
|
|
384
|
+
if (!Number.isInteger(operand) || operand < 0 || operand >= nOps) throw new Error(`Tensor.einsum: ${what} references operand ${operand}, but only ${nOps} operand(s) were given`);
|
|
385
|
+
const rank = operands[operand].shape.length;
|
|
386
|
+
if (!Number.isInteger(axis) || axis < 0 || axis >= rank) throw new Error(`Tensor.einsum: ${what} references axis ${axis} of operand ${operand}, which has rank ${rank}`);
|
|
387
|
+
const ref = operand + ":" + axis;
|
|
388
|
+
if (seenRefs.has(ref)) throw new Error(`Tensor.einsum: ${what} references axis ${axis} of operand ${operand} a second time; each operand axis may appear once`);
|
|
389
|
+
seenRefs.add(ref);
|
|
390
|
+
};
|
|
391
|
+
spec.free.forEach((fa, v) => checkRef(`free[${v}]`, fa.operand, fa.axis));
|
|
392
|
+
spec.contractions.forEach((c, v) => {
|
|
393
|
+
checkRef(`contractions[${v}] (first)`, c.pair[0][0], c.pair[0][1]);
|
|
394
|
+
checkRef(`contractions[${v}] (second)`, c.pair[1][0], c.pair[1][1]);
|
|
395
|
+
});
|
|
336
396
|
const inStrides = operands.map((o) => Tensor.rowMajorStrides(o.shape));
|
|
337
397
|
const freeSizes = spec.free.map((fa) => operands[fa.operand].shape[fa.axis]);
|
|
338
398
|
const contractSizes = spec.contractions.map((c) => {
|
|
339
399
|
const [[oa, axa], [ob, axb]] = c.pair;
|
|
340
|
-
const sa = operands[oa]
|
|
341
|
-
|
|
342
|
-
if (sa === void 0 || sb === void 0 || sa !== sb) throw new Error(`Tensor.einsum: contraction pair size mismatch`);
|
|
400
|
+
const sa = operands[oa].shape[axa];
|
|
401
|
+
if (sa !== operands[ob].shape[axb]) throw new Error(`Tensor.einsum: contraction pair size mismatch`);
|
|
343
402
|
return sa;
|
|
344
403
|
});
|
|
345
|
-
const outStrides = Tensor.rowMajorStrides(freeSizes);
|
|
346
404
|
const out = new Float64Array(Tensor.sizeOf(freeSizes));
|
|
347
|
-
for (let o = 0; o <
|
|
405
|
+
for (let o = 0; o < nOps; o++) {
|
|
348
406
|
if (operands[o].shape.length === 0) continue;
|
|
349
407
|
const covered = /* @__PURE__ */ new Set();
|
|
350
408
|
spec.free.forEach((fa) => {
|
|
@@ -357,27 +415,52 @@ var Tensor = class Tensor {
|
|
|
357
415
|
});
|
|
358
416
|
if (covered.size !== operands[o].shape.length) throw new Error(`Tensor.einsum: operand ${o} has axes not referenced by the spec`);
|
|
359
417
|
}
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
};
|
|
372
|
-
|
|
418
|
+
const nFree = freeSizes.length;
|
|
419
|
+
const nCon = contractSizes.length;
|
|
420
|
+
const freeContrib = operands.map(() => new Array(nFree).fill(0));
|
|
421
|
+
const conContrib = operands.map(() => new Array(nCon).fill(0));
|
|
422
|
+
spec.free.forEach((fa, v) => {
|
|
423
|
+
freeContrib[fa.operand][v] += inStrides[fa.operand][fa.axis];
|
|
424
|
+
});
|
|
425
|
+
spec.contractions.forEach((c, v) => {
|
|
426
|
+
const [[oa, axa], [ob, axb]] = c.pair;
|
|
427
|
+
conContrib[oa][v] += inStrides[oa][axa];
|
|
428
|
+
conContrib[ob][v] += inStrides[ob][axb];
|
|
429
|
+
});
|
|
430
|
+
const outSize = out.length;
|
|
431
|
+
const conSize = Tensor.sizeOf(contractSizes);
|
|
432
|
+
const datas = operands.map((o) => o.data);
|
|
433
|
+
const base = new Array(nOps).fill(0);
|
|
434
|
+
const cur = new Array(nOps).fill(0);
|
|
435
|
+
const freeCoords = new Array(nFree).fill(0);
|
|
436
|
+
const conCoords = new Array(nCon).fill(0);
|
|
437
|
+
for (let outN = 0; outN < outSize; outN++) {
|
|
438
|
+
for (let o = 0; o < nOps; o++) cur[o] = base[o];
|
|
439
|
+
conCoords.fill(0);
|
|
373
440
|
let acc = 0;
|
|
374
|
-
|
|
441
|
+
for (let cn = 0; cn < conSize; cn++) {
|
|
375
442
|
let product = 1;
|
|
376
|
-
for (let o = 0; o <
|
|
443
|
+
for (let o = 0; o < nOps; o++) product *= datas[o][cur[o]];
|
|
377
444
|
acc += product;
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
445
|
+
for (let k = nCon - 1; k >= 0; k--) {
|
|
446
|
+
if (++conCoords[k] < contractSizes[k]) {
|
|
447
|
+
for (let o = 0; o < nOps; o++) cur[o] += conContrib[o][k];
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
for (let o = 0; o < nOps; o++) cur[o] -= conContrib[o][k] * (contractSizes[k] - 1);
|
|
451
|
+
conCoords[k] = 0;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
out[outN] = acc;
|
|
455
|
+
for (let k = nFree - 1; k >= 0; k--) {
|
|
456
|
+
if (++freeCoords[k] < freeSizes[k]) {
|
|
457
|
+
for (let o = 0; o < nOps; o++) base[o] += freeContrib[o][k];
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
for (let o = 0; o < nOps; o++) base[o] -= freeContrib[o][k] * (freeSizes[k] - 1);
|
|
461
|
+
freeCoords[k] = 0;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
381
464
|
return new Tensor(freeSizes, out);
|
|
382
465
|
}
|
|
383
466
|
axisOf(index) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danielsimonjr/mathts-tensor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Rank-N dense Tensor type for MathTS with Float64Array-backed storage",
|
|
5
5
|
"author": "Daniel Simon Jr.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@danielsimonjr/mathts-core": "^0.
|
|
46
|
-
"@danielsimonjr/mathts-matrix": "^0.
|
|
45
|
+
"@danielsimonjr/mathts-core": "^0.22.0",
|
|
46
|
+
"@danielsimonjr/mathts-matrix": "^0.9.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@types/node": "^26.4.0",
|