@danielsimonjr/mathts-autograd 0.3.13 → 0.3.14

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.
@@ -0,0 +1,132 @@
1
+ /**
2
+ * DualTensor — a Tensor + per-element tangent component for forward-mode AD.
3
+ * Storage: two Float64Arrays of equal length (primal + tangent), shape from
4
+ * the wrapped Tensor. Arithmetic follows the dual-number rules:
5
+ * (a, a') + (b, b') = (a+b, a'+b')
6
+ * (a, a') * (b, b') = (a·b, a·b' + a'·b)
7
+ * (a, a') / (b, b') = (a/b, (a'·b − a·b')/b²)
8
+ * scale((a, a'), k) = (k·a, k·a')
9
+ * Elementwise unless noted. Reductions and contractions add their own rules.
10
+ *
11
+ * The dual-number framework: tracking ε such that ε²=0; (a + a'·ε)(b + b'·ε)
12
+ * = ab + (ab'+a'b)ε, so the tangent is the linearized first-order response.
13
+ *
14
+ * @packageDocumentation
15
+ */
16
+ import { Tensor } from '@danielsimonjr/mathts-tensor';
17
+ /**
18
+ * Holds a tensor value and its tangent for forward-mode automatic differentiation.
19
+ *
20
+ * The primal and the tangent are flat arrays of equal length, laid out by `shape`.
21
+ * The `data` getter returns the primal, so tensor ops that read `.data` accept a DualTensor.
22
+ *
23
+ * @throws Error from the constructor if the primal length and the tangent length differ.
24
+ */
25
+ export declare class DualTensor {
26
+ readonly shape: ReadonlyArray<number>;
27
+ readonly primal: Float64Array;
28
+ readonly tangent: Float64Array;
29
+ constructor(shape: ReadonlyArray<number>, primal: Float64Array, tangent: Float64Array);
30
+ /**
31
+ * S5 fix: existing engine ops (e.g. lower, pderiv, contract) reach into
32
+ * `.data`. The getter returns the primal so those ops still work when a
33
+ * DualTensor flows through them as a structurally-compatible Tensor.
34
+ * (AD-aware ops branch on `'tangent' in arg` before reaching here.)
35
+ */
36
+ get data(): Float64Array;
37
+ /** Lift a Tensor to a DualTensor with zero tangent. */
38
+ static fromTensor(t: Tensor): DualTensor;
39
+ /** Lift a Tensor to a DualTensor with a unit tangent at flat-index `i`. */
40
+ static unitAt(t: Tensor, i: number): DualTensor;
41
+ /** Extract the primal as a plain Tensor. */
42
+ toPrimalTensor(): Tensor;
43
+ /** Extract the tangent as a plain Tensor. */
44
+ toTangentTensor(): Tensor;
45
+ /** Elementwise addition following dual-number rule: (a+b, a'+b'). */
46
+ add(other: DualTensor): DualTensor;
47
+ /** Elementwise subtraction following dual-number rule: (a-b, a'-b'). */
48
+ sub(other: DualTensor): DualTensor;
49
+ /**
50
+ * Elementwise multiplication following dual-number rule: (a·b, a·b' + a'·b).
51
+ *
52
+ * I3 fix: explicit alias check. When `this === other` (self-multiplication),
53
+ * use the specialised rule (a·a)' = 2·a·a' directly. The general rule also
54
+ * degenerates correctly, but the explicit branch is more readable and aligns
55
+ * the forward-mode implementation with the reverse-mode alias fix.
56
+ */
57
+ mul(other: DualTensor): DualTensor;
58
+ /** Scalar multiplication following dual-number rule: (k·a, k·a'). */
59
+ scale(k: number): DualTensor;
60
+ /**
61
+ * Elementwise division following the dual-number quotient rule:
62
+ * (a, a') / (b, b') = (a/b, (a'·b − a·b') / b²).
63
+ * The aliased case a.divide(a) is (1, 0).
64
+ */
65
+ divide(other: DualTensor): DualTensor;
66
+ private _unaryElementwise;
67
+ /**
68
+ * Apply a shared elementary rule from core's `DUAL_UNARY_RULES` element-wise.
69
+ * Sourcing `primal`/`deriv` from the canonical table (rather than inline
70
+ * `Math.*`) keeps this AD path and the scalar `Dual` in lock-step and lets a
71
+ * future accelerated `primal` in the standard layer propagate here for free —
72
+ * the loop still calls plain scalar functions, so it stays allocation-free.
73
+ */
74
+ private _rule;
75
+ /** Exponential. f'(x) = eˣ = y. */
76
+ exp(): DualTensor;
77
+ /** Natural logarithm. f'(x) = 1/x. */
78
+ log(): DualTensor;
79
+ /** Sine. f'(x) = cos(x). */
80
+ sin(): DualTensor;
81
+ /** Cosine. f'(x) = −sin(x). */
82
+ cos(): DualTensor;
83
+ /** Tangent. f'(x) = 1/cos²(x). */
84
+ tan(): DualTensor;
85
+ /** Square root. f'(x) = 1/(2·y) where y = √x. */
86
+ sqrt(): DualTensor;
87
+ /** Square (x²). f'(x) = 2x. */
88
+ square(): DualTensor;
89
+ /** Reciprocal (1/x). f'(x) = −1/x². */
90
+ reciprocal(): DualTensor;
91
+ /** Absolute value. f'(x) = sign(x) (subgradient 0 at exact zero). */
92
+ abs(): DualTensor;
93
+ /** Fixed-exponent power x^k. f'(x) = k·x^(k−1). */
94
+ pow(k: number): DualTensor;
95
+ /** Hyperbolic sine. f'(x) = cosh(x). */
96
+ sinh(): DualTensor;
97
+ /** Hyperbolic cosine. f'(x) = sinh(x). */
98
+ cosh(): DualTensor;
99
+ /** Hyperbolic tangent. f'(x) = 1 − tanh²(x) = 1 − y². */
100
+ tanh(): DualTensor;
101
+ /** Arcsine. f'(x) = 1/√(1 − x²). */
102
+ asin(): DualTensor;
103
+ /** Arccosine. f'(x) = −1/√(1 − x²). */
104
+ acos(): DualTensor;
105
+ /** Arctangent. f'(x) = 1/(1 + x²). */
106
+ atan(): DualTensor;
107
+ /** Inverse hyperbolic sine. f'(x) = 1/√(x² + 1). */
108
+ asinh(): DualTensor;
109
+ /** Inverse hyperbolic cosine (x ≥ 1). f'(x) = 1/√(x² − 1). */
110
+ acosh(): DualTensor;
111
+ /** Inverse hyperbolic tangent (|x| < 1). f'(x) = 1/(1 − x²). */
112
+ atanh(): DualTensor;
113
+ /** Base-2 logarithm. f'(x) = 1/(x·ln2). */
114
+ log2(): DualTensor;
115
+ /** Base-10 logarithm. f'(x) = 1/(x·ln10). */
116
+ log10(): DualTensor;
117
+ /** log(1 + x). f'(x) = 1/(1 + x). */
118
+ log1p(): DualTensor;
119
+ /** exp(x) − 1. f'(x) = eˣ = y + 1. */
120
+ expm1(): DualTensor;
121
+ /** Cube root. f'(x) = 1/(3·y²) where y = x^(1/3) (→∞ at x = 0). */
122
+ cbrt(): DualTensor;
123
+ /** Sign (−1/0/+1). f'(x) = 0 almost everywhere. */
124
+ sign(): DualTensor;
125
+ /**
126
+ * Two-argument arctangent: atan2(this, other), this = y, other = x.
127
+ * Tangent: (b·a' − a·b') / (a² + b²), with a = this, b = other.
128
+ */
129
+ atan2(other: DualTensor): DualTensor;
130
+ private checkSameShape;
131
+ }
132
+ //# sourceMappingURL=dual-tensor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dual-tensor.d.ts","sourceRoot":"","sources":["../src/dual-tensor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Forward-mode AD via dual numbers. Returns the value and the full Jacobian
3
+ * of fn at x, shape [...value.shape, ...x.shape] (row-major flatten).
4
+ *
5
+ * Implementation: for each flat-index k in x, build a DualTensor with a unit
6
+ * tangent at position k, run fn (which operates on Tensors — see "interop"
7
+ * below), extract the tangent of the result. The tangent is the k-th column
8
+ * of the Jacobian (in row-major-of-output-flattened form).
9
+ *
10
+ * Interop with the Tensor type: fn is typed `(x: Tensor) => Tensor`, so the
11
+ * tracing requires fn's body to be implementable on either Tensor OR
12
+ * DualTensor. v0.1.0 ships a documented "trace mode" — if fn uses only the
13
+ * core ops that DualTensor implements (add/sub/mul/scale), the
14
+ * implementation auto-traces by detecting DualTensor inputs via a thin
15
+ * wrapper. The actual mechanism in v0.1.0: caller writes fn as if Tensor's
16
+ * methods accept either Tensor or DualTensor (TypeScript's structural typing
17
+ * makes this work for the implemented ops). v0.2.0 may broaden via decorator
18
+ * instrumentation.
19
+ *
20
+ * For UPT v0.4.0's call-sites (metric functions in christoffel lowering),
21
+ * fn uses only add/sub/mul/scale → safe.
22
+ *
23
+ * @packageDocumentation
24
+ */
25
+ import { Tensor } from '@danielsimonjr/mathts-tensor';
26
+ /**
27
+ * Compute the value and full Jacobian of `fn` at point `x` using forward-mode
28
+ * automatic differentiation (dual numbers).
29
+ *
30
+ * @param fn - Pure function operating on Tensors via add/sub/mul/scale.
31
+ * Must be traceable: at runtime it receives a DualTensor (structurally
32
+ * compatible with Tensor) and must return a DualTensor.
33
+ * @param x - Input tensor at which to differentiate.
34
+ * @returns `{ value, jacobian }` where:
35
+ * - `value` has the output shape of fn applied to x
36
+ * - `jacobian` has shape `[...value.shape, ...x.shape]` row-major.
37
+ * `jacobian.data[kY * xSize + kX]` = ∂y[kY] / ∂x[kX].
38
+ * Verified by Adam+Eve review 2026-05-15 (E13): kY outer, kX inner,
39
+ * stride xSize between successive y-rows IS row-major [...y.shape, ...x.shape].
40
+ */
41
+ export declare function forwardGrad(fn: (x: Tensor) => Tensor, x: Tensor): {
42
+ value: Tensor;
43
+ jacobian: Tensor;
44
+ };
45
+ //# sourceMappingURL=forward-grad.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forward-grad.d.ts","sourceRoot":"","sources":["../src/forward-grad.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAGtD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CACzB,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EACzB,CAAC,EAAE,MAAM,GACR;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAgDrC"}
package/dist/grad.d.ts ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * GC15 — ergonomic, number-friendly autodiff bridge.
3
+ *
4
+ * The low-level building blocks (`Tape`, `TapedTensor`, `reverseGrad`) require
5
+ * manual tape management and `Tensor` marshalling. This is the JAX-style
6
+ * convenience layer: write a function of a single `TapedTensor` (the AD-aware
7
+ * surface — `.sin()`, `.mul()`, `.sum()`, `.matmul()`, … all record adjoints)
8
+ * and differentiate it against plain JS numbers / arrays.
9
+ *
10
+ * grad((x) => x.sin())(1) // [cos(1)]
11
+ * valueAndGrad((x) => x.pow(2).sum())([1, 2, 3]) // { value: 14, grad: [2,4,6] }
12
+ * derivative((x) => x.sin().mul(x), 2) // sin(2) + 2cos(2)
13
+ *
14
+ * `f` must use TapedTensor operations (not the plain `functions/` ops, which are
15
+ * not AD-aware). Differentiating arbitrary `functions/` ops would require
16
+ * overloading them onto dual numbers / the tape — a separate, larger effort.
17
+ */
18
+ import { TapedTensor } from './tape.js';
19
+ /**
20
+ * Function that `valueAndGrad`, `grad`, `derivative` and `jacobian` differentiate.
21
+ *
22
+ * The function must build its result from TapedTensor operations only, because only these operations record adjoints.
23
+ * `valueAndGrad`, `grad` and `derivative` require a result of length 1. `jacobian` accepts a vector result.
24
+ */
25
+ export type ScalarFn = (x: TapedTensor) => TapedTensor;
26
+ /**
27
+ * Point at which a function is differentiated: a number, a number array, or a Float64Array.
28
+ *
29
+ * The helpers copy the input into a new Float64Array, so they do not change the caller's array.
30
+ */
31
+ export type NumericInput = number | readonly number[] | Float64Array;
32
+ /**
33
+ * Forward value and reverse-mode gradient of a scalar-valued function.
34
+ *
35
+ * @param fn maps a TapedTensor (shape `[n]`) to a scalar TapedTensor (length 1).
36
+ * @param x the point — a number, number[], or Float64Array.
37
+ * @returns `{ value, grad }` where `grad` has the same length as `x`.
38
+ * @throws if `fn` does not return a length-1 (scalar) result.
39
+ */
40
+ export declare function valueAndGrad(fn: ScalarFn, x: NumericInput): {
41
+ value: number;
42
+ grad: Float64Array;
43
+ };
44
+ /**
45
+ * Gradient function of a scalar-valued function: `grad(f)(x)` returns ∇f(x).
46
+ */
47
+ export declare function grad(fn: ScalarFn): (x: NumericInput) => Float64Array;
48
+ /**
49
+ * Scalar convenience: derivative of `f: ℝ → ℝ` at `x0`.
50
+ */
51
+ export declare function derivative(fn: ScalarFn, x0: number): number;
52
+ /**
53
+ * Jacobian of a vector-valued function `f: ℝⁿ → ℝᵐ`, one reverse pass per output
54
+ * row. Returns an `m × n` array. (For tall outputs forward-mode is cheaper; this
55
+ * favours wide-input / few-output cases, the common ML gradient shape.)
56
+ */
57
+ export declare function jacobian(fn: ScalarFn, x: NumericInput): number[][];
58
+ //# sourceMappingURL=grad.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grad.d.ts","sourceRoot":"","sources":["../src/grad.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAQ,WAAW,EAAE,MAAM,WAAW,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,EAAE,WAAW,KAAK,WAAW,CAAC;AACvD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,YAAY,CAAC;AAOrE;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,YAAY,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE,CAcjG;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,EAAE,EAAE,QAAQ,GAAG,CAAC,CAAC,EAAE,YAAY,KAAK,YAAY,CAEpE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,EAAE,EAAE,CAmBlE"}