@danielsimonjr/mathts-autograd 0.1.3 → 0.3.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/dist/index.d.ts +170 -6
- package/dist/index.js +382 -28
- package/package.json +58 -58
package/dist/index.d.ts
CHANGED
|
@@ -51,6 +51,68 @@ declare class DualTensor {
|
|
|
51
51
|
mul(other: DualTensor): DualTensor;
|
|
52
52
|
/** Scalar multiplication following dual-number rule: (k·a, k·a'). */
|
|
53
53
|
scale(k: number): DualTensor;
|
|
54
|
+
/**
|
|
55
|
+
* Elementwise division following the dual-number quotient rule:
|
|
56
|
+
* (a, a') / (b, b') = (a/b, (a'·b − a·b') / b²).
|
|
57
|
+
* The aliased case a.divide(a) is (1, 0).
|
|
58
|
+
*/
|
|
59
|
+
divide(other: DualTensor): DualTensor;
|
|
60
|
+
private _unaryElementwise;
|
|
61
|
+
/** Exponential. f'(x) = eˣ = y. */
|
|
62
|
+
exp(): DualTensor;
|
|
63
|
+
/** Natural logarithm. f'(x) = 1/x. */
|
|
64
|
+
log(): DualTensor;
|
|
65
|
+
/** Sine. f'(x) = cos(x). */
|
|
66
|
+
sin(): DualTensor;
|
|
67
|
+
/** Cosine. f'(x) = −sin(x). */
|
|
68
|
+
cos(): DualTensor;
|
|
69
|
+
/** Tangent. f'(x) = 1/cos²(x). */
|
|
70
|
+
tan(): DualTensor;
|
|
71
|
+
/** Square root. f'(x) = 1/(2·y) where y = √x. */
|
|
72
|
+
sqrt(): DualTensor;
|
|
73
|
+
/** Square (x²). f'(x) = 2x. */
|
|
74
|
+
square(): DualTensor;
|
|
75
|
+
/** Reciprocal (1/x). f'(x) = −1/x². */
|
|
76
|
+
reciprocal(): DualTensor;
|
|
77
|
+
/** Absolute value. f'(x) = sign(x) (subgradient 0 at exact zero). */
|
|
78
|
+
abs(): DualTensor;
|
|
79
|
+
/** Fixed-exponent power x^k. f'(x) = k·x^(k−1). */
|
|
80
|
+
pow(k: number): DualTensor;
|
|
81
|
+
/** Hyperbolic sine. f'(x) = cosh(x). */
|
|
82
|
+
sinh(): DualTensor;
|
|
83
|
+
/** Hyperbolic cosine. f'(x) = sinh(x). */
|
|
84
|
+
cosh(): DualTensor;
|
|
85
|
+
/** Hyperbolic tangent. f'(x) = 1 − tanh²(x) = 1 − y². */
|
|
86
|
+
tanh(): DualTensor;
|
|
87
|
+
/** Arcsine. f'(x) = 1/√(1 − x²). */
|
|
88
|
+
asin(): DualTensor;
|
|
89
|
+
/** Arccosine. f'(x) = −1/√(1 − x²). */
|
|
90
|
+
acos(): DualTensor;
|
|
91
|
+
/** Arctangent. f'(x) = 1/(1 + x²). */
|
|
92
|
+
atan(): DualTensor;
|
|
93
|
+
/** Inverse hyperbolic sine. f'(x) = 1/√(x² + 1). */
|
|
94
|
+
asinh(): DualTensor;
|
|
95
|
+
/** Inverse hyperbolic cosine (x ≥ 1). f'(x) = 1/√(x² − 1). */
|
|
96
|
+
acosh(): DualTensor;
|
|
97
|
+
/** Inverse hyperbolic tangent (|x| < 1). f'(x) = 1/(1 − x²). */
|
|
98
|
+
atanh(): DualTensor;
|
|
99
|
+
/** Base-2 logarithm. f'(x) = 1/(x·ln2). */
|
|
100
|
+
log2(): DualTensor;
|
|
101
|
+
/** Base-10 logarithm. f'(x) = 1/(x·ln10). */
|
|
102
|
+
log10(): DualTensor;
|
|
103
|
+
/** log(1 + x). f'(x) = 1/(1 + x). */
|
|
104
|
+
log1p(): DualTensor;
|
|
105
|
+
/** exp(x) − 1. f'(x) = eˣ = y + 1. */
|
|
106
|
+
expm1(): DualTensor;
|
|
107
|
+
/** Cube root. f'(x) = 1/(3·y²) where y = x^(1/3) (→∞ at x = 0). */
|
|
108
|
+
cbrt(): DualTensor;
|
|
109
|
+
/** Sign (−1/0/+1). f'(x) = 0 almost everywhere. */
|
|
110
|
+
sign(): DualTensor;
|
|
111
|
+
/**
|
|
112
|
+
* Two-argument arctangent: atan2(this, other), this = y, other = x.
|
|
113
|
+
* Tangent: (b·a' − a·b') / (a² + b²), with a = this, b = other.
|
|
114
|
+
*/
|
|
115
|
+
atan2(other: DualTensor): DualTensor;
|
|
54
116
|
private checkSameShape;
|
|
55
117
|
}
|
|
56
118
|
|
|
@@ -329,14 +391,21 @@ declare class TapedTensor {
|
|
|
329
391
|
*/
|
|
330
392
|
square(): TapedTensor;
|
|
331
393
|
/**
|
|
332
|
-
* Elementwise
|
|
394
|
+
* Elementwise power: x^k.
|
|
333
395
|
*
|
|
334
|
-
*
|
|
335
|
-
*
|
|
396
|
+
* `k` may be a fixed `number` (constant exponent) or a `TapedTensor`
|
|
397
|
+
* (variable exponent, both inputs on the tape).
|
|
336
398
|
*
|
|
337
|
-
*
|
|
399
|
+
* Adjoints, for y = a^b:
|
|
400
|
+
* - fixed exponent k: dA = dY · k · a^(k−1)
|
|
401
|
+
* - variable exponent: dA = dY · b · a^(b−1), dB = dY · a^b · ln(a)
|
|
402
|
+
* - aliased a^a: dA = dY · a^a · (ln a + 1)
|
|
403
|
+
*
|
|
404
|
+
* The dB term needs ln(a); for a ≤ 0 it is mathematically undefined and
|
|
405
|
+
* yields NaN/−Inf, honestly signalling non-differentiability w.r.t. the
|
|
406
|
+
* exponent rather than masking it.
|
|
338
407
|
*/
|
|
339
|
-
pow(k: number): TapedTensor;
|
|
408
|
+
pow(k: number | TapedTensor): TapedTensor;
|
|
340
409
|
/**
|
|
341
410
|
* Elementwise reciprocal: 1 / x.
|
|
342
411
|
*
|
|
@@ -350,6 +419,54 @@ declare class TapedTensor {
|
|
|
350
419
|
* Subgradient at exact zero is defined as 0 (rather than undefined).
|
|
351
420
|
*/
|
|
352
421
|
abs(): TapedTensor;
|
|
422
|
+
/**
|
|
423
|
+
* Build a reverse-mode node for an elementwise unary op.
|
|
424
|
+
* @param primalFn forward value y = f(x)
|
|
425
|
+
* @param localGrad local derivative dy/dx, given x and the computed y
|
|
426
|
+
*/
|
|
427
|
+
private _unaryElementwise;
|
|
428
|
+
/** Hyperbolic sine. Adjoint: dX = dY · cosh(x). */
|
|
429
|
+
sinh(): TapedTensor;
|
|
430
|
+
/** Hyperbolic cosine. Adjoint: dX = dY · sinh(x). */
|
|
431
|
+
cosh(): TapedTensor;
|
|
432
|
+
/** Hyperbolic tangent. Adjoint: dX = dY · (1 − tanh²(x)) = dY · (1 − y²). */
|
|
433
|
+
tanh(): TapedTensor;
|
|
434
|
+
/** Arcsine. Adjoint: dX = dY / √(1 − x²). */
|
|
435
|
+
asin(): TapedTensor;
|
|
436
|
+
/** Arccosine. Adjoint: dX = −dY / √(1 − x²). */
|
|
437
|
+
acos(): TapedTensor;
|
|
438
|
+
/** Arctangent. Adjoint: dX = dY / (1 + x²). */
|
|
439
|
+
atan(): TapedTensor;
|
|
440
|
+
/** Inverse hyperbolic sine. Adjoint: dX = dY / √(x² + 1). */
|
|
441
|
+
asinh(): TapedTensor;
|
|
442
|
+
/** Inverse hyperbolic cosine (x ≥ 1). Adjoint: dX = dY / √(x² − 1). */
|
|
443
|
+
acosh(): TapedTensor;
|
|
444
|
+
/** Inverse hyperbolic tangent (|x| < 1). Adjoint: dX = dY / (1 − x²). */
|
|
445
|
+
atanh(): TapedTensor;
|
|
446
|
+
/** Base-2 logarithm. Adjoint: dX = dY / (x · ln2). */
|
|
447
|
+
log2(): TapedTensor;
|
|
448
|
+
/** Base-10 logarithm. Adjoint: dX = dY / (x · ln10). */
|
|
449
|
+
log10(): TapedTensor;
|
|
450
|
+
/** log(1 + x) (accurate near 0). Adjoint: dX = dY / (1 + x). */
|
|
451
|
+
log1p(): TapedTensor;
|
|
452
|
+
/** exp(x) − 1 (accurate near 0). Adjoint: dX = dY · eˣ = dY · (y + 1). */
|
|
453
|
+
expm1(): TapedTensor;
|
|
454
|
+
/** Cube root. Adjoint: dX = dY / (3 · y²) where y = x^(1/3) (→∞ at x = 0). */
|
|
455
|
+
cbrt(): TapedTensor;
|
|
456
|
+
/** Sign of x (−1/0/+1). Adjoint: 0 almost everywhere. */
|
|
457
|
+
sign(): TapedTensor;
|
|
458
|
+
/**
|
|
459
|
+
* Two-argument arctangent: atan2(this, other), with this = y, other = x.
|
|
460
|
+
*
|
|
461
|
+
* Adjoints (a = this, b = other, d = a² + b²):
|
|
462
|
+
* dA = dY · b / d
|
|
463
|
+
* dB = −dY · a / d
|
|
464
|
+
*
|
|
465
|
+
* The aliased case atan2(a, a) is locally constant (±π/4 or ±3π/4), so its
|
|
466
|
+
* gradient is 0 — produced naturally by contributing nothing when aliased
|
|
467
|
+
* (dA + dB = dY · (b − a)/d = 0 at a = b).
|
|
468
|
+
*/
|
|
469
|
+
atan2(other: TapedTensor): TapedTensor;
|
|
353
470
|
/**
|
|
354
471
|
* Reverse-mode AD over `Tensor.tensordot`.
|
|
355
472
|
*
|
|
@@ -484,4 +601,51 @@ declare function reverseGrad(fn: (x: Tensor) => Tensor, x: Tensor, cotangent?: T
|
|
|
484
601
|
gradient: Tensor;
|
|
485
602
|
};
|
|
486
603
|
|
|
487
|
-
|
|
604
|
+
/**
|
|
605
|
+
* GC15 — ergonomic, number-friendly autodiff bridge.
|
|
606
|
+
*
|
|
607
|
+
* The low-level building blocks (`Tape`, `TapedTensor`, `reverseGrad`) require
|
|
608
|
+
* manual tape management and `Tensor` marshalling. This is the JAX-style
|
|
609
|
+
* convenience layer: write a function of a single `TapedTensor` (the AD-aware
|
|
610
|
+
* surface — `.sin()`, `.mul()`, `.sum()`, `.matmul()`, … all record adjoints)
|
|
611
|
+
* and differentiate it against plain JS numbers / arrays.
|
|
612
|
+
*
|
|
613
|
+
* grad((x) => x.sin())(1) // [cos(1)]
|
|
614
|
+
* valueAndGrad((x) => x.pow(2).sum())([1, 2, 3]) // { value: 14, grad: [2,4,6] }
|
|
615
|
+
* derivative((x) => x.sin().mul(x), 2) // sin(2) + 2cos(2)
|
|
616
|
+
*
|
|
617
|
+
* `f` must use TapedTensor operations (not the plain `functions/` ops, which are
|
|
618
|
+
* not AD-aware). Differentiating arbitrary `functions/` ops would require
|
|
619
|
+
* overloading them onto dual numbers / the tape — a separate, larger effort.
|
|
620
|
+
*/
|
|
621
|
+
|
|
622
|
+
type ScalarFn = (x: TapedTensor) => TapedTensor;
|
|
623
|
+
type NumericInput = number | readonly number[] | Float64Array;
|
|
624
|
+
/**
|
|
625
|
+
* Forward value and reverse-mode gradient of a scalar-valued function.
|
|
626
|
+
*
|
|
627
|
+
* @param fn maps a TapedTensor (shape `[n]`) to a scalar TapedTensor (length 1).
|
|
628
|
+
* @param x the point — a number, number[], or Float64Array.
|
|
629
|
+
* @returns `{ value, grad }` where `grad` has the same length as `x`.
|
|
630
|
+
* @throws if `fn` does not return a length-1 (scalar) result.
|
|
631
|
+
*/
|
|
632
|
+
declare function valueAndGrad(fn: ScalarFn, x: NumericInput): {
|
|
633
|
+
value: number;
|
|
634
|
+
grad: Float64Array;
|
|
635
|
+
};
|
|
636
|
+
/**
|
|
637
|
+
* Gradient function of a scalar-valued function: `grad(f)(x)` returns ∇f(x).
|
|
638
|
+
*/
|
|
639
|
+
declare function grad(fn: ScalarFn): (x: NumericInput) => Float64Array;
|
|
640
|
+
/**
|
|
641
|
+
* Scalar convenience: derivative of `f: ℝ → ℝ` at `x0`.
|
|
642
|
+
*/
|
|
643
|
+
declare function derivative(fn: ScalarFn, x0: number): number;
|
|
644
|
+
/**
|
|
645
|
+
* Jacobian of a vector-valued function `f: ℝⁿ → ℝᵐ`, one reverse pass per output
|
|
646
|
+
* row. Returns an `m × n` array. (For tall outputs forward-mode is cheaper; this
|
|
647
|
+
* favours wide-input / few-output cases, the common ML gradient shape.)
|
|
648
|
+
*/
|
|
649
|
+
declare function jacobian(fn: ScalarFn, x: NumericInput): number[][];
|
|
650
|
+
|
|
651
|
+
export { DualTensor, type NumericInput, type ScalarFn, Tape, TapedTensor, derivative, forwardGrad, grad, jacobian, reverseGrad, valueAndGrad };
|
package/dist/index.js
CHANGED
|
@@ -98,6 +98,172 @@ var DualTensor = class _DualTensor {
|
|
|
98
98
|
}
|
|
99
99
|
return new _DualTensor(this.shape, p, t);
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Elementwise division following the dual-number quotient rule:
|
|
103
|
+
* (a, a') / (b, b') = (a/b, (a'·b − a·b') / b²).
|
|
104
|
+
* The aliased case a.divide(a) is (1, 0).
|
|
105
|
+
*/
|
|
106
|
+
divide(other) {
|
|
107
|
+
this.checkSameShape(other, "divide");
|
|
108
|
+
const p = new Float64Array(this.primal.length);
|
|
109
|
+
const t = new Float64Array(this.tangent.length);
|
|
110
|
+
if (this === other) {
|
|
111
|
+
for (let i = 0; i < p.length; i++) {
|
|
112
|
+
p[i] = 1;
|
|
113
|
+
t[i] = 0;
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
for (let i = 0; i < p.length; i++) {
|
|
117
|
+
const a = this.primal[i];
|
|
118
|
+
const b = other.primal[i];
|
|
119
|
+
p[i] = a / b;
|
|
120
|
+
t[i] = (this.tangent[i] * b - a * other.tangent[i]) / (b * b);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return new _DualTensor(this.shape, p, t);
|
|
124
|
+
}
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Elementwise unary ops (parity with reverse-mode TapedTensor). Each follows
|
|
127
|
+
// the dual-number rule (a, a') ↦ (f(a), f'(a)·a'), built via the
|
|
128
|
+
// `_unaryElementwise` helper. `deriv(x, y)` is f'(x) given input x and the
|
|
129
|
+
// computed output y (so adjoints needing y — exp, tanh, sqrt — stay uniform).
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
_unaryElementwise(primalFn, deriv) {
|
|
132
|
+
const p = new Float64Array(this.primal.length);
|
|
133
|
+
const t = new Float64Array(this.tangent.length);
|
|
134
|
+
for (let i = 0; i < p.length; i++) {
|
|
135
|
+
const y = primalFn(this.primal[i]);
|
|
136
|
+
p[i] = y;
|
|
137
|
+
t[i] = deriv(this.primal[i], y) * this.tangent[i];
|
|
138
|
+
}
|
|
139
|
+
return new _DualTensor(this.shape, p, t);
|
|
140
|
+
}
|
|
141
|
+
/** Exponential. f'(x) = eˣ = y. */
|
|
142
|
+
exp() {
|
|
143
|
+
return this._unaryElementwise(Math.exp, (_x, y) => y);
|
|
144
|
+
}
|
|
145
|
+
/** Natural logarithm. f'(x) = 1/x. */
|
|
146
|
+
log() {
|
|
147
|
+
return this._unaryElementwise(Math.log, (x) => 1 / x);
|
|
148
|
+
}
|
|
149
|
+
/** Sine. f'(x) = cos(x). */
|
|
150
|
+
sin() {
|
|
151
|
+
return this._unaryElementwise(Math.sin, (x) => Math.cos(x));
|
|
152
|
+
}
|
|
153
|
+
/** Cosine. f'(x) = −sin(x). */
|
|
154
|
+
cos() {
|
|
155
|
+
return this._unaryElementwise(Math.cos, (x) => -Math.sin(x));
|
|
156
|
+
}
|
|
157
|
+
/** Tangent. f'(x) = 1/cos²(x). */
|
|
158
|
+
tan() {
|
|
159
|
+
return this._unaryElementwise(Math.tan, (x) => 1 / (Math.cos(x) * Math.cos(x)));
|
|
160
|
+
}
|
|
161
|
+
/** Square root. f'(x) = 1/(2·y) where y = √x. */
|
|
162
|
+
sqrt() {
|
|
163
|
+
return this._unaryElementwise(Math.sqrt, (_x, y) => 1 / (2 * y));
|
|
164
|
+
}
|
|
165
|
+
/** Square (x²). f'(x) = 2x. */
|
|
166
|
+
square() {
|
|
167
|
+
return this._unaryElementwise(
|
|
168
|
+
(x) => x * x,
|
|
169
|
+
(x) => 2 * x
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
/** Reciprocal (1/x). f'(x) = −1/x². */
|
|
173
|
+
reciprocal() {
|
|
174
|
+
return this._unaryElementwise(
|
|
175
|
+
(x) => 1 / x,
|
|
176
|
+
(x) => -1 / (x * x)
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
/** Absolute value. f'(x) = sign(x) (subgradient 0 at exact zero). */
|
|
180
|
+
abs() {
|
|
181
|
+
return this._unaryElementwise(Math.abs, (x) => Math.sign(x));
|
|
182
|
+
}
|
|
183
|
+
/** Fixed-exponent power x^k. f'(x) = k·x^(k−1). */
|
|
184
|
+
pow(k) {
|
|
185
|
+
return this._unaryElementwise(
|
|
186
|
+
(x) => Math.pow(x, k),
|
|
187
|
+
(x) => k * Math.pow(x, k - 1)
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
/** Hyperbolic sine. f'(x) = cosh(x). */
|
|
191
|
+
sinh() {
|
|
192
|
+
return this._unaryElementwise(Math.sinh, (x) => Math.cosh(x));
|
|
193
|
+
}
|
|
194
|
+
/** Hyperbolic cosine. f'(x) = sinh(x). */
|
|
195
|
+
cosh() {
|
|
196
|
+
return this._unaryElementwise(Math.cosh, (x) => Math.sinh(x));
|
|
197
|
+
}
|
|
198
|
+
/** Hyperbolic tangent. f'(x) = 1 − tanh²(x) = 1 − y². */
|
|
199
|
+
tanh() {
|
|
200
|
+
return this._unaryElementwise(Math.tanh, (_x, y) => 1 - y * y);
|
|
201
|
+
}
|
|
202
|
+
/** Arcsine. f'(x) = 1/√(1 − x²). */
|
|
203
|
+
asin() {
|
|
204
|
+
return this._unaryElementwise(Math.asin, (x) => 1 / Math.sqrt(1 - x * x));
|
|
205
|
+
}
|
|
206
|
+
/** Arccosine. f'(x) = −1/√(1 − x²). */
|
|
207
|
+
acos() {
|
|
208
|
+
return this._unaryElementwise(Math.acos, (x) => -1 / Math.sqrt(1 - x * x));
|
|
209
|
+
}
|
|
210
|
+
/** Arctangent. f'(x) = 1/(1 + x²). */
|
|
211
|
+
atan() {
|
|
212
|
+
return this._unaryElementwise(Math.atan, (x) => 1 / (1 + x * x));
|
|
213
|
+
}
|
|
214
|
+
/** Inverse hyperbolic sine. f'(x) = 1/√(x² + 1). */
|
|
215
|
+
asinh() {
|
|
216
|
+
return this._unaryElementwise(Math.asinh, (x) => 1 / Math.sqrt(x * x + 1));
|
|
217
|
+
}
|
|
218
|
+
/** Inverse hyperbolic cosine (x ≥ 1). f'(x) = 1/√(x² − 1). */
|
|
219
|
+
acosh() {
|
|
220
|
+
return this._unaryElementwise(Math.acosh, (x) => 1 / Math.sqrt(x * x - 1));
|
|
221
|
+
}
|
|
222
|
+
/** Inverse hyperbolic tangent (|x| < 1). f'(x) = 1/(1 − x²). */
|
|
223
|
+
atanh() {
|
|
224
|
+
return this._unaryElementwise(Math.atanh, (x) => 1 / (1 - x * x));
|
|
225
|
+
}
|
|
226
|
+
/** Base-2 logarithm. f'(x) = 1/(x·ln2). */
|
|
227
|
+
log2() {
|
|
228
|
+
return this._unaryElementwise(Math.log2, (x) => 1 / (x * Math.LN2));
|
|
229
|
+
}
|
|
230
|
+
/** Base-10 logarithm. f'(x) = 1/(x·ln10). */
|
|
231
|
+
log10() {
|
|
232
|
+
return this._unaryElementwise(Math.log10, (x) => 1 / (x * Math.LN10));
|
|
233
|
+
}
|
|
234
|
+
/** log(1 + x). f'(x) = 1/(1 + x). */
|
|
235
|
+
log1p() {
|
|
236
|
+
return this._unaryElementwise(Math.log1p, (x) => 1 / (1 + x));
|
|
237
|
+
}
|
|
238
|
+
/** exp(x) − 1. f'(x) = eˣ = y + 1. */
|
|
239
|
+
expm1() {
|
|
240
|
+
return this._unaryElementwise(Math.expm1, (_x, y) => y + 1);
|
|
241
|
+
}
|
|
242
|
+
/** Cube root. f'(x) = 1/(3·y²) where y = x^(1/3) (→∞ at x = 0). */
|
|
243
|
+
cbrt() {
|
|
244
|
+
return this._unaryElementwise(Math.cbrt, (_x, y) => 1 / (3 * y * y));
|
|
245
|
+
}
|
|
246
|
+
/** Sign (−1/0/+1). f'(x) = 0 almost everywhere. */
|
|
247
|
+
sign() {
|
|
248
|
+
return this._unaryElementwise(Math.sign, () => 0);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Two-argument arctangent: atan2(this, other), this = y, other = x.
|
|
252
|
+
* Tangent: (b·a' − a·b') / (a² + b²), with a = this, b = other.
|
|
253
|
+
*/
|
|
254
|
+
atan2(other) {
|
|
255
|
+
this.checkSameShape(other, "atan2");
|
|
256
|
+
const p = new Float64Array(this.primal.length);
|
|
257
|
+
const t = new Float64Array(this.tangent.length);
|
|
258
|
+
for (let i = 0; i < p.length; i++) {
|
|
259
|
+
const a = this.primal[i];
|
|
260
|
+
const b = other.primal[i];
|
|
261
|
+
p[i] = Math.atan2(a, b);
|
|
262
|
+
const d = a * a + b * b;
|
|
263
|
+
t[i] = (b * this.tangent[i] - a * other.tangent[i]) / d;
|
|
264
|
+
}
|
|
265
|
+
return new _DualTensor(this.shape, p, t);
|
|
266
|
+
}
|
|
101
267
|
checkSameShape(other, op) {
|
|
102
268
|
if (this.shape.length !== other.shape.length || !this.shape.every((v, i) => v === other.shape[i])) {
|
|
103
269
|
throw new Error(`DualTensor.${op}: shape mismatch [${this.shape}] vs [${other.shape}]`);
|
|
@@ -492,8 +658,8 @@ var TapedTensor = class _TapedTensor {
|
|
|
492
658
|
const thisGradSlot = this.tape.getInputGrad(this.id);
|
|
493
659
|
const { id } = this.tape.record([this.id], outT.data.length, (outputGrad) => {
|
|
494
660
|
const outShape = [...outT.shape];
|
|
495
|
-
const outStrides =
|
|
496
|
-
const inStrides =
|
|
661
|
+
const outStrides = Tensor3.rowMajorStrides(outShape);
|
|
662
|
+
const inStrides = Tensor3.rowMajorStrides(inputShape);
|
|
497
663
|
const inCoords = new Array(inputShape.length).fill(0);
|
|
498
664
|
for (let n = 0; n < inputSize; n++) {
|
|
499
665
|
let outFlat = 0;
|
|
@@ -536,7 +702,7 @@ var TapedTensor = class _TapedTensor {
|
|
|
536
702
|
const thisGradSlot = this.tape.getInputGrad(this.id);
|
|
537
703
|
const { id } = this.tape.record([this.id], outT.data.length, (outputGrad) => {
|
|
538
704
|
const outShape = [...outT.shape];
|
|
539
|
-
const outStrides =
|
|
705
|
+
const outStrides = Tensor3.rowMajorStrides(outShape);
|
|
540
706
|
const inCoords = new Array(inputShape.length).fill(0);
|
|
541
707
|
for (let n = 0; n < inputSize; n++) {
|
|
542
708
|
let outFlat = 0;
|
|
@@ -584,8 +750,8 @@ var TapedTensor = class _TapedTensor {
|
|
|
584
750
|
const thisGradSlot = this.tape.getInputGrad(this.id);
|
|
585
751
|
const { id } = this.tape.record([this.id], outT.data.length, (outputGrad) => {
|
|
586
752
|
const outShape = [...outT.shape];
|
|
587
|
-
const outStrides =
|
|
588
|
-
const inStrides =
|
|
753
|
+
const outStrides = Tensor3.rowMajorStrides(outShape);
|
|
754
|
+
const inStrides = Tensor3.rowMajorStrides(inputShape);
|
|
589
755
|
const groups = /* @__PURE__ */ new Map();
|
|
590
756
|
const inCoords = new Array(inputShape.length).fill(0);
|
|
591
757
|
for (let n = 0; n < primalData.length; n++) {
|
|
@@ -649,7 +815,7 @@ var TapedTensor = class _TapedTensor {
|
|
|
649
815
|
const thisGradSlot = this.tape.getInputGrad(this.id);
|
|
650
816
|
const { id } = this.tape.record([this.id], outT.data.length, (outputGrad) => {
|
|
651
817
|
const outShape = [...outT.shape];
|
|
652
|
-
const outStrides =
|
|
818
|
+
const outStrides = Tensor3.rowMajorStrides(outShape);
|
|
653
819
|
const argmaxSlot = new Int32Array(outT.data.length).fill(-1);
|
|
654
820
|
const inCoords = new Array(inputShape.length).fill(0);
|
|
655
821
|
for (let n = 0; n < primalData.length; n++) {
|
|
@@ -698,7 +864,7 @@ var TapedTensor = class _TapedTensor {
|
|
|
698
864
|
const thisGradSlot = this.tape.getInputGrad(this.id);
|
|
699
865
|
const { id } = this.tape.record([this.id], outT.data.length, (outputGrad) => {
|
|
700
866
|
const outShape = [...outT.shape];
|
|
701
|
-
const outStrides =
|
|
867
|
+
const outStrides = Tensor3.rowMajorStrides(outShape);
|
|
702
868
|
const argminSlot = new Int32Array(outT.data.length).fill(-1);
|
|
703
869
|
const inCoords = new Array(inputShape.length).fill(0);
|
|
704
870
|
for (let n = 0; n < primalData.length; n++) {
|
|
@@ -756,7 +922,7 @@ var TapedTensor = class _TapedTensor {
|
|
|
756
922
|
const normData = new Float64Array(outT.data);
|
|
757
923
|
const { id } = this.tape.record([this.id], outT.data.length, (outputGrad) => {
|
|
758
924
|
const outShape = [...outT.shape];
|
|
759
|
-
const outStrides =
|
|
925
|
+
const outStrides = Tensor3.rowMajorStrides(outShape);
|
|
760
926
|
const inCoords = new Array(inputShape.length).fill(0);
|
|
761
927
|
for (let n = 0; n < primalData.length; n++) {
|
|
762
928
|
let outFlat = 0;
|
|
@@ -784,7 +950,7 @@ var TapedTensor = class _TapedTensor {
|
|
|
784
950
|
if (p === 1) {
|
|
785
951
|
const { id } = this.tape.record([this.id], outT.data.length, (outputGrad) => {
|
|
786
952
|
const outShape = [...outT.shape];
|
|
787
|
-
const outStrides =
|
|
953
|
+
const outStrides = Tensor3.rowMajorStrides(outShape);
|
|
788
954
|
const inCoords = new Array(inputShape.length).fill(0);
|
|
789
955
|
for (let n = 0; n < primalData.length; n++) {
|
|
790
956
|
let outFlat = 0;
|
|
@@ -811,7 +977,7 @@ var TapedTensor = class _TapedTensor {
|
|
|
811
977
|
{
|
|
812
978
|
const { id } = this.tape.record([this.id], outT.data.length, (outputGrad) => {
|
|
813
979
|
const outShape = [...outT.shape];
|
|
814
|
-
const outStrides =
|
|
980
|
+
const outStrides = Tensor3.rowMajorStrides(outShape);
|
|
815
981
|
const argmaxAbsSlot = new Int32Array(outT.data.length).fill(-1);
|
|
816
982
|
const inCoords = new Array(inputShape.length).fill(0);
|
|
817
983
|
for (let n = 0; n < primalData.length; n++) {
|
|
@@ -979,21 +1145,55 @@ var TapedTensor = class _TapedTensor {
|
|
|
979
1145
|
return new _TapedTensor(this.shape, out, this.tape, id);
|
|
980
1146
|
}
|
|
981
1147
|
/**
|
|
982
|
-
* Elementwise
|
|
1148
|
+
* Elementwise power: x^k.
|
|
983
1149
|
*
|
|
984
|
-
*
|
|
985
|
-
*
|
|
1150
|
+
* `k` may be a fixed `number` (constant exponent) or a `TapedTensor`
|
|
1151
|
+
* (variable exponent, both inputs on the tape).
|
|
986
1152
|
*
|
|
987
|
-
*
|
|
1153
|
+
* Adjoints, for y = a^b:
|
|
1154
|
+
* - fixed exponent k: dA = dY · k · a^(k−1)
|
|
1155
|
+
* - variable exponent: dA = dY · b · a^(b−1), dB = dY · a^b · ln(a)
|
|
1156
|
+
* - aliased a^a: dA = dY · a^a · (ln a + 1)
|
|
1157
|
+
*
|
|
1158
|
+
* The dB term needs ln(a); for a ≤ 0 it is mathematically undefined and
|
|
1159
|
+
* yields NaN/−Inf, honestly signalling non-differentiability w.r.t. the
|
|
1160
|
+
* exponent rather than masking it.
|
|
988
1161
|
*/
|
|
989
1162
|
pow(k) {
|
|
1163
|
+
if (typeof k === "number") {
|
|
1164
|
+
const out2 = new Float64Array(this.primal.length);
|
|
1165
|
+
for (let i = 0; i < out2.length; i++) out2[i] = Math.pow(this.primal[i], k);
|
|
1166
|
+
const primalData = new Float64Array(this.primal);
|
|
1167
|
+
const thisGradSlot2 = this.tape.getInputGrad(this.id);
|
|
1168
|
+
const { id: id2 } = this.tape.record([this.id], out2.length, (outputGrad) => {
|
|
1169
|
+
for (let i = 0; i < outputGrad.length; i++) {
|
|
1170
|
+
thisGradSlot2[i] += outputGrad[i] * k * Math.pow(primalData[i], k - 1);
|
|
1171
|
+
}
|
|
1172
|
+
});
|
|
1173
|
+
return new _TapedTensor(this.shape, out2, this.tape, id2);
|
|
1174
|
+
}
|
|
1175
|
+
const other = k;
|
|
1176
|
+
this.checkSameShape(other, "pow");
|
|
990
1177
|
const out = new Float64Array(this.primal.length);
|
|
991
|
-
for (let i = 0; i < out.length; i++) out[i] = Math.pow(this.primal[i],
|
|
992
|
-
const
|
|
1178
|
+
for (let i = 0; i < out.length; i++) out[i] = Math.pow(this.primal[i], other.primal[i]);
|
|
1179
|
+
const aPrimal = new Float64Array(this.primal);
|
|
1180
|
+
const bPrimal = new Float64Array(other.primal);
|
|
1181
|
+
const yPrimal = new Float64Array(out);
|
|
993
1182
|
const thisGradSlot = this.tape.getInputGrad(this.id);
|
|
994
|
-
const
|
|
1183
|
+
const otherGradSlot = this.tape.getInputGrad(other.id);
|
|
1184
|
+
const isAliased = this === other;
|
|
1185
|
+
const { id } = this.tape.record([this.id, other.id], out.length, (outputGrad) => {
|
|
995
1186
|
for (let i = 0; i < outputGrad.length; i++) {
|
|
996
|
-
|
|
1187
|
+
const a = aPrimal[i];
|
|
1188
|
+
const b = bPrimal[i];
|
|
1189
|
+
const y = yPrimal[i];
|
|
1190
|
+
const g = outputGrad[i];
|
|
1191
|
+
if (isAliased) {
|
|
1192
|
+
thisGradSlot[i] += g * y * (Math.log(a) + 1);
|
|
1193
|
+
} else {
|
|
1194
|
+
thisGradSlot[i] += g * b * Math.pow(a, b - 1);
|
|
1195
|
+
otherGradSlot[i] += g * y * Math.log(a);
|
|
1196
|
+
}
|
|
997
1197
|
}
|
|
998
1198
|
});
|
|
999
1199
|
return new _TapedTensor(this.shape, out, this.tape, id);
|
|
@@ -1037,6 +1237,121 @@ var TapedTensor = class _TapedTensor {
|
|
|
1037
1237
|
return new _TapedTensor(this.shape, out, this.tape, id);
|
|
1038
1238
|
}
|
|
1039
1239
|
// ---------------------------------------------------------------------------
|
|
1240
|
+
// Extended elementwise transcendentals (hyperbolic, inverse-trig, log/exp
|
|
1241
|
+
// variants, sign, cbrt, atan2). Each builds a reverse-mode node via the
|
|
1242
|
+
// `_unaryElementwise` helper; `localGrad(x, y)` is dy/dx given input x and
|
|
1243
|
+
// output y. The helper caches both x and y so adjoints that need either
|
|
1244
|
+
// (e.g. tanh needs y, log needs x) are uniform.
|
|
1245
|
+
// ---------------------------------------------------------------------------
|
|
1246
|
+
/**
|
|
1247
|
+
* Build a reverse-mode node for an elementwise unary op.
|
|
1248
|
+
* @param primalFn forward value y = f(x)
|
|
1249
|
+
* @param localGrad local derivative dy/dx, given x and the computed y
|
|
1250
|
+
*/
|
|
1251
|
+
_unaryElementwise(primalFn, localGrad) {
|
|
1252
|
+
const xData = new Float64Array(this.primal);
|
|
1253
|
+
const out = new Float64Array(xData.length);
|
|
1254
|
+
for (let i = 0; i < out.length; i++) out[i] = primalFn(xData[i]);
|
|
1255
|
+
const yData = new Float64Array(out);
|
|
1256
|
+
const thisGradSlot = this.tape.getInputGrad(this.id);
|
|
1257
|
+
const { id } = this.tape.record([this.id], out.length, (outputGrad) => {
|
|
1258
|
+
for (let i = 0; i < outputGrad.length; i++) {
|
|
1259
|
+
thisGradSlot[i] += outputGrad[i] * localGrad(xData[i], yData[i]);
|
|
1260
|
+
}
|
|
1261
|
+
});
|
|
1262
|
+
return new _TapedTensor(this.shape, out, this.tape, id);
|
|
1263
|
+
}
|
|
1264
|
+
/** Hyperbolic sine. Adjoint: dX = dY · cosh(x). */
|
|
1265
|
+
sinh() {
|
|
1266
|
+
return this._unaryElementwise(Math.sinh, (x) => Math.cosh(x));
|
|
1267
|
+
}
|
|
1268
|
+
/** Hyperbolic cosine. Adjoint: dX = dY · sinh(x). */
|
|
1269
|
+
cosh() {
|
|
1270
|
+
return this._unaryElementwise(Math.cosh, (x) => Math.sinh(x));
|
|
1271
|
+
}
|
|
1272
|
+
/** Hyperbolic tangent. Adjoint: dX = dY · (1 − tanh²(x)) = dY · (1 − y²). */
|
|
1273
|
+
tanh() {
|
|
1274
|
+
return this._unaryElementwise(Math.tanh, (_x, y) => 1 - y * y);
|
|
1275
|
+
}
|
|
1276
|
+
/** Arcsine. Adjoint: dX = dY / √(1 − x²). */
|
|
1277
|
+
asin() {
|
|
1278
|
+
return this._unaryElementwise(Math.asin, (x) => 1 / Math.sqrt(1 - x * x));
|
|
1279
|
+
}
|
|
1280
|
+
/** Arccosine. Adjoint: dX = −dY / √(1 − x²). */
|
|
1281
|
+
acos() {
|
|
1282
|
+
return this._unaryElementwise(Math.acos, (x) => -1 / Math.sqrt(1 - x * x));
|
|
1283
|
+
}
|
|
1284
|
+
/** Arctangent. Adjoint: dX = dY / (1 + x²). */
|
|
1285
|
+
atan() {
|
|
1286
|
+
return this._unaryElementwise(Math.atan, (x) => 1 / (1 + x * x));
|
|
1287
|
+
}
|
|
1288
|
+
/** Inverse hyperbolic sine. Adjoint: dX = dY / √(x² + 1). */
|
|
1289
|
+
asinh() {
|
|
1290
|
+
return this._unaryElementwise(Math.asinh, (x) => 1 / Math.sqrt(x * x + 1));
|
|
1291
|
+
}
|
|
1292
|
+
/** Inverse hyperbolic cosine (x ≥ 1). Adjoint: dX = dY / √(x² − 1). */
|
|
1293
|
+
acosh() {
|
|
1294
|
+
return this._unaryElementwise(Math.acosh, (x) => 1 / Math.sqrt(x * x - 1));
|
|
1295
|
+
}
|
|
1296
|
+
/** Inverse hyperbolic tangent (|x| < 1). Adjoint: dX = dY / (1 − x²). */
|
|
1297
|
+
atanh() {
|
|
1298
|
+
return this._unaryElementwise(Math.atanh, (x) => 1 / (1 - x * x));
|
|
1299
|
+
}
|
|
1300
|
+
/** Base-2 logarithm. Adjoint: dX = dY / (x · ln2). */
|
|
1301
|
+
log2() {
|
|
1302
|
+
return this._unaryElementwise(Math.log2, (x) => 1 / (x * Math.LN2));
|
|
1303
|
+
}
|
|
1304
|
+
/** Base-10 logarithm. Adjoint: dX = dY / (x · ln10). */
|
|
1305
|
+
log10() {
|
|
1306
|
+
return this._unaryElementwise(Math.log10, (x) => 1 / (x * Math.LN10));
|
|
1307
|
+
}
|
|
1308
|
+
/** log(1 + x) (accurate near 0). Adjoint: dX = dY / (1 + x). */
|
|
1309
|
+
log1p() {
|
|
1310
|
+
return this._unaryElementwise(Math.log1p, (x) => 1 / (1 + x));
|
|
1311
|
+
}
|
|
1312
|
+
/** exp(x) − 1 (accurate near 0). Adjoint: dX = dY · eˣ = dY · (y + 1). */
|
|
1313
|
+
expm1() {
|
|
1314
|
+
return this._unaryElementwise(Math.expm1, (_x, y) => y + 1);
|
|
1315
|
+
}
|
|
1316
|
+
/** Cube root. Adjoint: dX = dY / (3 · y²) where y = x^(1/3) (→∞ at x = 0). */
|
|
1317
|
+
cbrt() {
|
|
1318
|
+
return this._unaryElementwise(Math.cbrt, (_x, y) => 1 / (3 * y * y));
|
|
1319
|
+
}
|
|
1320
|
+
/** Sign of x (−1/0/+1). Adjoint: 0 almost everywhere. */
|
|
1321
|
+
sign() {
|
|
1322
|
+
return this._unaryElementwise(Math.sign, () => 0);
|
|
1323
|
+
}
|
|
1324
|
+
/**
|
|
1325
|
+
* Two-argument arctangent: atan2(this, other), with this = y, other = x.
|
|
1326
|
+
*
|
|
1327
|
+
* Adjoints (a = this, b = other, d = a² + b²):
|
|
1328
|
+
* dA = dY · b / d
|
|
1329
|
+
* dB = −dY · a / d
|
|
1330
|
+
*
|
|
1331
|
+
* The aliased case atan2(a, a) is locally constant (±π/4 or ±3π/4), so its
|
|
1332
|
+
* gradient is 0 — produced naturally by contributing nothing when aliased
|
|
1333
|
+
* (dA + dB = dY · (b − a)/d = 0 at a = b).
|
|
1334
|
+
*/
|
|
1335
|
+
atan2(other) {
|
|
1336
|
+
this.checkSameShape(other, "atan2");
|
|
1337
|
+
const a = new Float64Array(this.primal);
|
|
1338
|
+
const b = new Float64Array(other.primal);
|
|
1339
|
+
const out = new Float64Array(a.length);
|
|
1340
|
+
for (let i = 0; i < out.length; i++) out[i] = Math.atan2(a[i], b[i]);
|
|
1341
|
+
const thisGradSlot = this.tape.getInputGrad(this.id);
|
|
1342
|
+
const otherGradSlot = this.tape.getInputGrad(other.id);
|
|
1343
|
+
const isAliased = this === other;
|
|
1344
|
+
const { id } = this.tape.record([this.id, other.id], out.length, (outputGrad) => {
|
|
1345
|
+
if (isAliased) return;
|
|
1346
|
+
for (let i = 0; i < outputGrad.length; i++) {
|
|
1347
|
+
const d = a[i] * a[i] + b[i] * b[i];
|
|
1348
|
+
thisGradSlot[i] += outputGrad[i] * b[i] / d;
|
|
1349
|
+
otherGradSlot[i] += -outputGrad[i] * a[i] / d;
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
return new _TapedTensor(this.shape, out, this.tape, id);
|
|
1353
|
+
}
|
|
1354
|
+
// ---------------------------------------------------------------------------
|
|
1040
1355
|
// tensordot — generalised dot product over explicit axis pairs.
|
|
1041
1356
|
// ---------------------------------------------------------------------------
|
|
1042
1357
|
/**
|
|
@@ -1658,15 +1973,6 @@ function _resolveAxes(axis, rank) {
|
|
|
1658
1973
|
}
|
|
1659
1974
|
return [...axis].sort((a, b) => a - b);
|
|
1660
1975
|
}
|
|
1661
|
-
function _rowMajorStrides(shape) {
|
|
1662
|
-
const strides = new Array(shape.length);
|
|
1663
|
-
let acc = 1;
|
|
1664
|
-
for (let k = shape.length - 1; k >= 0; k--) {
|
|
1665
|
-
strides[k] = acc;
|
|
1666
|
-
acc *= shape[k];
|
|
1667
|
-
}
|
|
1668
|
-
return strides;
|
|
1669
|
-
}
|
|
1670
1976
|
function _scatterToOriginalAxes(tensor, targetLabels) {
|
|
1671
1977
|
const currentLabels = tensor.axisLabels;
|
|
1672
1978
|
const rank = targetLabels.length;
|
|
@@ -1795,10 +2101,58 @@ function reverseGrad(fn, x, cotangent) {
|
|
|
1795
2101
|
gradient: new Tensor4(x.shape, new Float64Array(xGradSlot))
|
|
1796
2102
|
};
|
|
1797
2103
|
}
|
|
2104
|
+
|
|
2105
|
+
// src/grad.ts
|
|
2106
|
+
function toFloat64(x) {
|
|
2107
|
+
if (typeof x === "number") return Float64Array.of(x);
|
|
2108
|
+
return x instanceof Float64Array ? new Float64Array(x) : Float64Array.from(x);
|
|
2109
|
+
}
|
|
2110
|
+
function valueAndGrad(fn, x) {
|
|
2111
|
+
const xs = toFloat64(x);
|
|
2112
|
+
const tape = new Tape();
|
|
2113
|
+
const { id } = tape.allocate(xs.length);
|
|
2114
|
+
const leaf = new TapedTensor([xs.length], xs, tape, id);
|
|
2115
|
+
const out = fn(leaf);
|
|
2116
|
+
if (out.primal.length !== 1) {
|
|
2117
|
+
throw new Error(
|
|
2118
|
+
`valueAndGrad: fn must return a scalar (length 1); got length ${out.primal.length}. Reduce with .sum()/.mean(), or use jacobian() for vector outputs.`
|
|
2119
|
+
);
|
|
2120
|
+
}
|
|
2121
|
+
tape.backward(out.id, Float64Array.of(1));
|
|
2122
|
+
return { value: out.primal[0], grad: new Float64Array(tape.getInputGrad(id)) };
|
|
2123
|
+
}
|
|
2124
|
+
function grad(fn) {
|
|
2125
|
+
return (x) => valueAndGrad(fn, x).grad;
|
|
2126
|
+
}
|
|
2127
|
+
function derivative(fn, x0) {
|
|
2128
|
+
return valueAndGrad(fn, x0).grad[0];
|
|
2129
|
+
}
|
|
2130
|
+
function jacobian(fn, x) {
|
|
2131
|
+
const xs = toFloat64(x);
|
|
2132
|
+
const probeTape = new Tape();
|
|
2133
|
+
const { id: probeId } = probeTape.allocate(xs.length);
|
|
2134
|
+
const probeOut = fn(new TapedTensor([xs.length], new Float64Array(xs), probeTape, probeId));
|
|
2135
|
+
const m = probeOut.primal.length;
|
|
2136
|
+
const rows = [];
|
|
2137
|
+
for (let r = 0; r < m; r++) {
|
|
2138
|
+
const tape = new Tape();
|
|
2139
|
+
const { id } = tape.allocate(xs.length);
|
|
2140
|
+
const out = fn(new TapedTensor([xs.length], new Float64Array(xs), tape, id));
|
|
2141
|
+
const seed = new Float64Array(m);
|
|
2142
|
+
seed[r] = 1;
|
|
2143
|
+
tape.backward(out.id, seed);
|
|
2144
|
+
rows.push(Array.from(tape.getInputGrad(id)));
|
|
2145
|
+
}
|
|
2146
|
+
return rows;
|
|
2147
|
+
}
|
|
1798
2148
|
export {
|
|
1799
2149
|
DualTensor,
|
|
1800
2150
|
Tape,
|
|
1801
2151
|
TapedTensor,
|
|
2152
|
+
derivative,
|
|
1802
2153
|
forwardGrad,
|
|
1803
|
-
|
|
2154
|
+
grad,
|
|
2155
|
+
jacobian,
|
|
2156
|
+
reverseGrad,
|
|
2157
|
+
valueAndGrad
|
|
1804
2158
|
};
|
package/package.json
CHANGED
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@danielsimonjr/mathts-autograd",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Forward + reverse-mode automatic differentiation for MathTS rank-N Tensor",
|
|
5
|
-
"author": "Daniel Simon Jr.",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"main": "./dist/index.js",
|
|
9
|
-
"module": "./dist/index.js",
|
|
10
|
-
"types": "./dist/index.d.ts",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"import": "./dist/index.js",
|
|
14
|
-
"types": "./dist/index.d.ts"
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"dist",
|
|
19
|
-
"README.md"
|
|
20
|
-
],
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
23
|
-
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
24
|
-
"test": "vitest run",
|
|
25
|
-
"test:watch": "vitest",
|
|
26
|
-
"test:coverage": "vitest run --coverage",
|
|
27
|
-
"typecheck": "tsc --noEmit",
|
|
28
|
-
"lint": "eslint src --ext .ts",
|
|
29
|
-
"lint:fix": "eslint src --ext .ts --fix",
|
|
30
|
-
"clean": "rm -rf dist",
|
|
31
|
-
"build:prod": "tsup src/index.ts --format esm --dts --clean --minify --treeshake"
|
|
32
|
-
},
|
|
33
|
-
"dependencies": {
|
|
34
|
-
"@danielsimonjr/mathts-core": "^0.1.4",
|
|
35
|
-
"@danielsimonjr/mathts-tensor": "^0.
|
|
36
|
-
},
|
|
37
|
-
"devDependencies": {
|
|
38
|
-
"@types/node": "^25.5.2",
|
|
39
|
-
"tsup": "^8.0.0",
|
|
40
|
-
"typescript": "^5.3.0",
|
|
41
|
-
"vitest": "^4.1.5"
|
|
42
|
-
},
|
|
43
|
-
"publishConfig": {
|
|
44
|
-
"access": "public"
|
|
45
|
-
},
|
|
46
|
-
"repository": {
|
|
47
|
-
"type": "git",
|
|
48
|
-
"url": "https://github.com/danielsimonjr/mathts",
|
|
49
|
-
"directory": "autograd"
|
|
50
|
-
},
|
|
51
|
-
"keywords": [
|
|
52
|
-
"math",
|
|
53
|
-
"autograd",
|
|
54
|
-
"automatic-differentiation",
|
|
55
|
-
"tensor",
|
|
56
|
-
"typescript"
|
|
57
|
-
]
|
|
58
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@danielsimonjr/mathts-autograd",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Forward + reverse-mode automatic differentiation for MathTS rank-N Tensor",
|
|
5
|
+
"author": "Daniel Simon Jr.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
23
|
+
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest",
|
|
26
|
+
"test:coverage": "vitest run --coverage",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"lint": "eslint src --ext .ts",
|
|
29
|
+
"lint:fix": "eslint src --ext .ts --fix",
|
|
30
|
+
"clean": "rm -rf dist",
|
|
31
|
+
"build:prod": "tsup src/index.ts --format esm --dts --clean --minify --treeshake"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@danielsimonjr/mathts-core": "^0.1.4",
|
|
35
|
+
"@danielsimonjr/mathts-tensor": "^0.2.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^25.5.2",
|
|
39
|
+
"tsup": "^8.0.0",
|
|
40
|
+
"typescript": "^5.3.0",
|
|
41
|
+
"vitest": "^4.1.5"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/danielsimonjr/mathts",
|
|
49
|
+
"directory": "autograd"
|
|
50
|
+
},
|
|
51
|
+
"keywords": [
|
|
52
|
+
"math",
|
|
53
|
+
"autograd",
|
|
54
|
+
"automatic-differentiation",
|
|
55
|
+
"tensor",
|
|
56
|
+
"typescript"
|
|
57
|
+
]
|
|
58
|
+
}
|