@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 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;
@@ -1 +1 @@
1
- {"version":3,"file":"Tensor.d.ts","sourceRoot":"","sources":["../src/Tensor.ts"],"names":[],"mappings":"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"}
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
- const nested = m.toArray();
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.fromArray(this.toNested());
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(this.data.length);
80
- for (let i = 0; i < this.data.length; i++) out[i] = this.data[i] + other;
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(this.data.length);
89
- for (let i = 0; i < this.data.length; i++) out[i] = this.data[i] - other;
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
- if (this.sameShape(other)) return this.elementwise(other, "mul", (x, y) => x * y);
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 out = new Float64Array(this.data.length);
102
- for (let i = 0; i < this.data.length; i++) out[i] = this.data[i] * k;
103
- return new Tensor(this.shape, out);
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 inCoords = new Array(rank).fill(0);
174
- const inSize = this.data.length;
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
- outFlat += inCoords[k] * outStrides[outDim];
220
+ contrib[k] = outStrides[outDim];
182
221
  outDim++;
183
222
  }
184
- out[outFlat] = combine(out[outFlat], this.data[n]);
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]) break;
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 outStrides = Tensor.rowMajorStrides(outShape);
319
- const out = new Float64Array(this.data.length);
320
- Tensor.forEachIndex(outShape, (outIdx) => {
321
- const inIdx = new Array(rank);
322
- for (let k = 0; k < rank; k++) inIdx[p[k]] = outIdx[k];
323
- out[Tensor.flatIndex(outIdx, outStrides)] = this.data[Tensor.flatIndex(inIdx, inStrides)];
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]?.shape[axa];
341
- const sb = operands[ob]?.shape[axb];
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 < operands.length; 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 operandFlatIndex = (opIndex, freeVals, contractVals) => {
361
- const idx = new Array(operands[opIndex].shape.length).fill(0);
362
- spec.free.forEach((fa, v) => {
363
- if (fa.operand === opIndex) idx[fa.axis] = freeVals[v];
364
- });
365
- spec.contractions.forEach((c, v) => {
366
- const [[oa, axa], [ob, axb]] = c.pair;
367
- if (oa === opIndex) idx[axa] = contractVals[v];
368
- if (ob === opIndex) idx[axb] = contractVals[v];
369
- });
370
- return Tensor.flatIndex(idx, inStrides[opIndex]);
371
- };
372
- Tensor.forEachIndex(freeSizes, (freeVals) => {
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
- Tensor.forEachIndex(contractSizes, (contractVals) => {
441
+ for (let cn = 0; cn < conSize; cn++) {
375
442
  let product = 1;
376
- for (let o = 0; o < operands.length; o++) product *= operands[o].data[operandFlatIndex(o, freeVals, contractVals)];
443
+ for (let o = 0; o < nOps; o++) product *= datas[o][cur[o]];
377
444
  acc += product;
378
- });
379
- out[Tensor.flatIndex(freeVals, outStrides)] = acc;
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.2.27",
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.21.0",
46
- "@danielsimonjr/mathts-matrix": "^0.8.1"
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",