scalar-autograd 0.1.7 → 0.1.9

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.
Files changed (86) hide show
  1. package/README.md +127 -2
  2. package/dist/CompiledFunctions.d.ts +111 -0
  3. package/dist/CompiledFunctions.js +268 -0
  4. package/dist/CompiledResiduals.d.ts +74 -0
  5. package/dist/CompiledResiduals.js +94 -0
  6. package/dist/EigenvalueHelpers.d.ts +14 -0
  7. package/dist/EigenvalueHelpers.js +93 -0
  8. package/dist/Geometry.d.ts +131 -0
  9. package/dist/Geometry.js +213 -0
  10. package/dist/GraphBuilder.d.ts +64 -0
  11. package/dist/GraphBuilder.js +237 -0
  12. package/dist/GraphCanonicalizerNoSort.d.ts +20 -0
  13. package/dist/GraphCanonicalizerNoSort.js +190 -0
  14. package/dist/GraphHashCanonicalizer.d.ts +46 -0
  15. package/dist/GraphHashCanonicalizer.js +220 -0
  16. package/dist/GraphSignature.d.ts +7 -0
  17. package/dist/GraphSignature.js +7 -0
  18. package/dist/KernelPool.d.ts +55 -0
  19. package/dist/KernelPool.js +124 -0
  20. package/dist/LBFGS.d.ts +84 -0
  21. package/dist/LBFGS.js +313 -0
  22. package/dist/LinearSolver.d.ts +69 -0
  23. package/dist/LinearSolver.js +213 -0
  24. package/dist/Losses.d.ts +9 -0
  25. package/dist/Losses.js +42 -37
  26. package/dist/Matrix3x3.d.ts +50 -0
  27. package/dist/Matrix3x3.js +146 -0
  28. package/dist/NonlinearLeastSquares.d.ts +33 -0
  29. package/dist/NonlinearLeastSquares.js +252 -0
  30. package/dist/Optimizers.d.ts +70 -14
  31. package/dist/Optimizers.js +42 -19
  32. package/dist/V.d.ts +0 -0
  33. package/dist/V.js +0 -0
  34. package/dist/Value.d.ts +84 -2
  35. package/dist/Value.js +296 -58
  36. package/dist/ValueActivation.js +10 -14
  37. package/dist/ValueArithmetic.d.ts +1 -0
  38. package/dist/ValueArithmetic.js +58 -50
  39. package/dist/ValueComparison.js +9 -13
  40. package/dist/ValueRegistry.d.ts +38 -0
  41. package/dist/ValueRegistry.js +88 -0
  42. package/dist/ValueTrig.js +14 -18
  43. package/dist/Vec2.d.ts +45 -0
  44. package/dist/Vec2.js +93 -0
  45. package/dist/Vec3.d.ts +78 -0
  46. package/dist/Vec3.js +169 -0
  47. package/dist/Vec4.d.ts +45 -0
  48. package/dist/Vec4.js +126 -0
  49. package/dist/__tests__/duplicate-inputs.test.js +33 -0
  50. package/dist/cli/gradient-gen.d.ts +19 -0
  51. package/dist/cli/gradient-gen.js +264 -0
  52. package/dist/compileIndirectKernel.d.ts +24 -0
  53. package/dist/compileIndirectKernel.js +148 -0
  54. package/dist/index.d.ts +20 -0
  55. package/dist/index.js +20 -0
  56. package/dist/scalar-autograd.d.ts +1157 -0
  57. package/dist/symbolic/AST.d.ts +113 -0
  58. package/dist/symbolic/AST.js +128 -0
  59. package/dist/symbolic/CodeGen.d.ts +35 -0
  60. package/dist/symbolic/CodeGen.js +280 -0
  61. package/dist/symbolic/Parser.d.ts +64 -0
  62. package/dist/symbolic/Parser.js +329 -0
  63. package/dist/symbolic/Simplify.d.ts +10 -0
  64. package/dist/symbolic/Simplify.js +244 -0
  65. package/dist/symbolic/SymbolicDiff.d.ts +35 -0
  66. package/dist/symbolic/SymbolicDiff.js +339 -0
  67. package/dist/tsdoc-metadata.json +11 -0
  68. package/package.json +29 -5
  69. package/dist/Losses.spec.js +0 -54
  70. package/dist/Optimizers.edge-cases.spec.d.ts +0 -1
  71. package/dist/Optimizers.edge-cases.spec.js +0 -29
  72. package/dist/Optimizers.spec.d.ts +0 -1
  73. package/dist/Optimizers.spec.js +0 -56
  74. package/dist/Value.edge-cases.spec.d.ts +0 -1
  75. package/dist/Value.edge-cases.spec.js +0 -54
  76. package/dist/Value.grad-flow.spec.d.ts +0 -1
  77. package/dist/Value.grad-flow.spec.js +0 -24
  78. package/dist/Value.losses-edge-cases.spec.d.ts +0 -1
  79. package/dist/Value.losses-edge-cases.spec.js +0 -30
  80. package/dist/Value.memory.spec.d.ts +0 -1
  81. package/dist/Value.memory.spec.js +0 -23
  82. package/dist/Value.nn.spec.d.ts +0 -1
  83. package/dist/Value.nn.spec.js +0 -111
  84. package/dist/Value.spec.d.ts +0 -1
  85. package/dist/Value.spec.js +0 -245
  86. /package/dist/{Losses.spec.d.ts → __tests__/duplicate-inputs.test.d.ts} +0 -0
package/dist/Vec3.d.ts ADDED
@@ -0,0 +1,78 @@
1
+ import { Value } from './Value';
2
+ /**
3
+ * 3D vector class with differentiable operations.
4
+ * @public
5
+ */
6
+ export declare class Vec3 {
7
+ x: Value;
8
+ y: Value;
9
+ z: Value;
10
+ constructor(x: Value | number, y: Value | number, z: Value | number);
11
+ static W(x: number, y: number, z: number): Vec3;
12
+ static C(x: number, y: number, z: number): Vec3;
13
+ static zero(): Vec3;
14
+ static one(): Vec3;
15
+ get magnitude(): Value;
16
+ get sqrMagnitude(): Value;
17
+ get normalized(): Vec3;
18
+ /**
19
+ * Normalized vector with custom analytical gradients.
20
+ * More efficient than autodiff through magnitude and division.
21
+ *
22
+ * Gradient formula: ∂(v/|v|)/∂v = (I - nn^T)/|v| where n = v/|v|
23
+ */
24
+ normalizedCustomGrad(): Vec3;
25
+ static dot(a: Vec3, b: Vec3): Value;
26
+ static cross(a: Vec3, b: Vec3): Vec3;
27
+ add(other: Vec3): Vec3;
28
+ sub(other: Vec3): Vec3;
29
+ mul(scalar: Value | number): Vec3;
30
+ div(scalar: Value | number): Vec3;
31
+ get trainables(): Value[];
32
+ toString(): string;
33
+ /**
34
+ * Compute angle between two vectors in radians.
35
+ * Returns value in range [0, π].
36
+ */
37
+ static angleBetween(a: Vec3, b: Vec3): Value;
38
+ /**
39
+ * Project vector a onto vector b.
40
+ */
41
+ static project(a: Vec3, b: Vec3): Vec3;
42
+ /**
43
+ * Reject vector a from vector b (component of a perpendicular to b).
44
+ */
45
+ static reject(a: Vec3, b: Vec3): Vec3;
46
+ /**
47
+ * Linear interpolation between two vectors.
48
+ */
49
+ static lerp(a: Vec3, b: Vec3, t: Value | number): Vec3;
50
+ /**
51
+ * Component-wise minimum.
52
+ */
53
+ static min(a: Vec3, b: Vec3): Vec3;
54
+ /**
55
+ * Component-wise maximum.
56
+ */
57
+ static max(a: Vec3, b: Vec3): Vec3;
58
+ /**
59
+ * Clone this vector (create new Vec3 with same values but independent graph).
60
+ */
61
+ clone(): Vec3;
62
+ /**
63
+ * Create Vec3 from raw data (no gradients).
64
+ */
65
+ static fromData(x: number, y: number, z: number): Vec3;
66
+ /**
67
+ * Extract raw data as array [x, y, z].
68
+ */
69
+ toArray(): number[];
70
+ /**
71
+ * Distance between two points.
72
+ */
73
+ static distance(a: Vec3, b: Vec3): Value;
74
+ /**
75
+ * Squared distance (faster, no sqrt).
76
+ */
77
+ static sqrDistance(a: Vec3, b: Vec3): Value;
78
+ }
package/dist/Vec3.js ADDED
@@ -0,0 +1,169 @@
1
+ import { V } from './V';
2
+ import { Value } from './Value';
3
+ /**
4
+ * 3D vector class with differentiable operations.
5
+ * @public
6
+ */
7
+ export class Vec3 {
8
+ x;
9
+ y;
10
+ z;
11
+ constructor(x, y, z) {
12
+ this.x = typeof x === 'number' ? new Value(x) : x;
13
+ this.y = typeof y === 'number' ? new Value(y) : y;
14
+ this.z = typeof z === 'number' ? new Value(z) : z;
15
+ }
16
+ static W(x, y, z) {
17
+ return new Vec3(V.W(x), V.W(y), V.W(z));
18
+ }
19
+ static C(x, y, z) {
20
+ return new Vec3(V.C(x), V.C(y), V.C(z));
21
+ }
22
+ static zero() {
23
+ return new Vec3(V.C(0), V.C(0), V.C(0));
24
+ }
25
+ static one() {
26
+ return new Vec3(V.C(1), V.C(1), V.C(1));
27
+ }
28
+ get magnitude() {
29
+ return V.sqrt(V.add(V.add(V.square(this.x), V.square(this.y)), V.square(this.z)));
30
+ }
31
+ get sqrMagnitude() {
32
+ return V.add(V.add(V.square(this.x), V.square(this.y)), V.square(this.z));
33
+ }
34
+ get normalized() {
35
+ const mag = this.magnitude;
36
+ return new Vec3(V.div(this.x, mag), V.div(this.y, mag), V.div(this.z, mag));
37
+ }
38
+ /**
39
+ * Normalized vector with custom analytical gradients.
40
+ * More efficient than autodiff through magnitude and division.
41
+ *
42
+ * Gradient formula: ∂(v/|v|)/∂v = (I - nn^T)/|v| where n = v/|v|
43
+ */
44
+ normalizedCustomGrad() {
45
+ // Forward pass: compute normalized vector using .data (no autodiff graph)
46
+ const mag = Math.sqrt(this.x.data * this.x.data + this.y.data * this.y.data + this.z.data * this.z.data);
47
+ const nx = this.x.data / mag;
48
+ const ny = this.y.data / mag;
49
+ const nz = this.z.data / mag;
50
+ const invMag = 1.0 / mag;
51
+ // Create output Values with custom backward pass
52
+ const outX = Value.makeNary(nx, [this.x, this.y, this.z], (out) => () => {
53
+ // ∂nx/∂vx = (1 - nx*nx)/|v|, ∂nx/∂vy = -nx*ny/|v|, ∂nx/∂vz = -nx*nz/|v|
54
+ this.x.grad += out.grad * (1 - nx * nx) * invMag;
55
+ this.y.grad += out.grad * (-nx * ny) * invMag;
56
+ this.z.grad += out.grad * (-nx * nz) * invMag;
57
+ }, 'normalize_x', 'normalize_x');
58
+ const outY = Value.makeNary(ny, [this.x, this.y, this.z], (out) => () => {
59
+ // ∂ny/∂vx = -ny*nx/|v|, ∂ny/∂vy = (1 - ny*ny)/|v|, ∂ny/∂vz = -ny*nz/|v|
60
+ this.x.grad += out.grad * (-ny * nx) * invMag;
61
+ this.y.grad += out.grad * (1 - ny * ny) * invMag;
62
+ this.z.grad += out.grad * (-ny * nz) * invMag;
63
+ }, 'normalize_y', 'normalize_y');
64
+ const outZ = Value.makeNary(nz, [this.x, this.y, this.z], (out) => () => {
65
+ // ∂nz/∂vx = -nz*nx/|v|, ∂nz/∂vy = -nz*ny/|v|, ∂nz/∂vz = (1 - nz*nz)/|v|
66
+ this.x.grad += out.grad * (-nz * nx) * invMag;
67
+ this.y.grad += out.grad * (-nz * ny) * invMag;
68
+ this.z.grad += out.grad * (1 - nz * nz) * invMag;
69
+ }, 'normalize_z', 'normalize_z');
70
+ return new Vec3(outX, outY, outZ);
71
+ }
72
+ static dot(a, b) {
73
+ return V.add(V.add(V.mul(a.x, b.x), V.mul(a.y, b.y)), V.mul(a.z, b.z));
74
+ }
75
+ static cross(a, b) {
76
+ return new Vec3(V.sub(V.mul(a.y, b.z), V.mul(a.z, b.y)), V.sub(V.mul(a.z, b.x), V.mul(a.x, b.z)), V.sub(V.mul(a.x, b.y), V.mul(a.y, b.x)));
77
+ }
78
+ add(other) {
79
+ return new Vec3(V.add(this.x, other.x), V.add(this.y, other.y), V.add(this.z, other.z));
80
+ }
81
+ sub(other) {
82
+ return new Vec3(V.sub(this.x, other.x), V.sub(this.y, other.y), V.sub(this.z, other.z));
83
+ }
84
+ mul(scalar) {
85
+ return new Vec3(V.mul(this.x, scalar), V.mul(this.y, scalar), V.mul(this.z, scalar));
86
+ }
87
+ div(scalar) {
88
+ return new Vec3(V.div(this.x, scalar), V.div(this.y, scalar), V.div(this.z, scalar));
89
+ }
90
+ get trainables() {
91
+ return [this.x, this.y, this.z];
92
+ }
93
+ toString() {
94
+ return `Vec3(${this.x.data}, ${this.y.data}, ${this.z.data})`;
95
+ }
96
+ /**
97
+ * Compute angle between two vectors in radians.
98
+ * Returns value in range [0, π].
99
+ */
100
+ static angleBetween(a, b) {
101
+ const dotProd = Vec3.dot(a, b);
102
+ const magProduct = V.mul(a.magnitude, b.magnitude);
103
+ const cosAngle = V.div(dotProd, magProduct);
104
+ return V.acos(V.clamp(cosAngle, -1, 1)); // Clamp for numerical stability
105
+ }
106
+ /**
107
+ * Project vector a onto vector b.
108
+ */
109
+ static project(a, b) {
110
+ const bMagSq = b.sqrMagnitude;
111
+ const scale = V.div(Vec3.dot(a, b), bMagSq);
112
+ return b.mul(scale);
113
+ }
114
+ /**
115
+ * Reject vector a from vector b (component of a perpendicular to b).
116
+ */
117
+ static reject(a, b) {
118
+ return a.sub(Vec3.project(a, b));
119
+ }
120
+ /**
121
+ * Linear interpolation between two vectors.
122
+ */
123
+ static lerp(a, b, t) {
124
+ const oneMinusT = V.sub(1, t);
125
+ return new Vec3(V.add(V.mul(a.x, oneMinusT), V.mul(b.x, t)), V.add(V.mul(a.y, oneMinusT), V.mul(b.y, t)), V.add(V.mul(a.z, oneMinusT), V.mul(b.z, t)));
126
+ }
127
+ /**
128
+ * Component-wise minimum.
129
+ */
130
+ static min(a, b) {
131
+ return new Vec3(V.min(a.x, b.x), V.min(a.y, b.y), V.min(a.z, b.z));
132
+ }
133
+ /**
134
+ * Component-wise maximum.
135
+ */
136
+ static max(a, b) {
137
+ return new Vec3(V.max(a.x, b.x), V.max(a.y, b.y), V.max(a.z, b.z));
138
+ }
139
+ /**
140
+ * Clone this vector (create new Vec3 with same values but independent graph).
141
+ */
142
+ clone() {
143
+ return new Vec3(new Value(this.x.data), new Value(this.y.data), new Value(this.z.data));
144
+ }
145
+ /**
146
+ * Create Vec3 from raw data (no gradients).
147
+ */
148
+ static fromData(x, y, z) {
149
+ return Vec3.C(x, y, z);
150
+ }
151
+ /**
152
+ * Extract raw data as array [x, y, z].
153
+ */
154
+ toArray() {
155
+ return [this.x.data, this.y.data, this.z.data];
156
+ }
157
+ /**
158
+ * Distance between two points.
159
+ */
160
+ static distance(a, b) {
161
+ return a.sub(b).magnitude;
162
+ }
163
+ /**
164
+ * Squared distance (faster, no sqrt).
165
+ */
166
+ static sqrDistance(a, b) {
167
+ return a.sub(b).sqrMagnitude;
168
+ }
169
+ }
package/dist/Vec4.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ import { Value } from 'scalar-autograd';
2
+ /**
3
+ * 4D vector class with differentiable operations.
4
+ * Primarily used for quaternions (w, x, y, z) where w is the scalar part.
5
+ */
6
+ export declare class Vec4 {
7
+ w: Value;
8
+ x: Value;
9
+ y: Value;
10
+ z: Value;
11
+ constructor(w: Value | number, x: Value | number, y: Value | number, z: Value | number);
12
+ static W(w: number, x: number, y: number, z: number): Vec4;
13
+ static C(w: number, x: number, y: number, z: number): Vec4;
14
+ static zero(): Vec4;
15
+ static identity(): Vec4;
16
+ get magnitude(): Value;
17
+ get sqrMagnitude(): Value;
18
+ get normalized(): Vec4;
19
+ /**
20
+ * Normalized quaternion with custom analytical gradients.
21
+ * More efficient than autodiff through magnitude and division.
22
+ *
23
+ * Gradient formula: ∂(q/|q|)/∂q = (I - nn^T)/|q| where n = q/|q|
24
+ */
25
+ normalizedCustomGrad(): Vec4;
26
+ static dot(a: Vec4, b: Vec4): Value;
27
+ add(other: Vec4): Vec4;
28
+ sub(other: Vec4): Vec4;
29
+ mul(scalar: Value | number): Vec4;
30
+ div(scalar: Value | number): Vec4;
31
+ get trainables(): Value[];
32
+ toString(): string;
33
+ /**
34
+ * Clone this vector (create new Vec4 with same values but independent graph).
35
+ */
36
+ clone(): Vec4;
37
+ /**
38
+ * Create Vec4 from raw data (no gradients).
39
+ */
40
+ static fromData(w: number, x: number, y: number, z: number): Vec4;
41
+ /**
42
+ * Extract raw data as array [w, x, y, z].
43
+ */
44
+ toArray(): [number, number, number, number];
45
+ }
package/dist/Vec4.js ADDED
@@ -0,0 +1,126 @@
1
+ import { V } from 'scalar-autograd';
2
+ import { Value } from 'scalar-autograd';
3
+ /**
4
+ * 4D vector class with differentiable operations.
5
+ * Primarily used for quaternions (w, x, y, z) where w is the scalar part.
6
+ */
7
+ export class Vec4 {
8
+ w;
9
+ x;
10
+ y;
11
+ z;
12
+ constructor(w, x, y, z) {
13
+ this.w = typeof w === 'number' ? new Value(w) : w;
14
+ this.x = typeof x === 'number' ? new Value(x) : x;
15
+ this.y = typeof y === 'number' ? new Value(y) : y;
16
+ this.z = typeof z === 'number' ? new Value(z) : z;
17
+ }
18
+ static W(w, x, y, z) {
19
+ return new Vec4(V.W(w), V.W(x), V.W(y), V.W(z));
20
+ }
21
+ static C(w, x, y, z) {
22
+ return new Vec4(V.C(w), V.C(x), V.C(y), V.C(z));
23
+ }
24
+ static zero() {
25
+ return new Vec4(V.C(0), V.C(0), V.C(0), V.C(0));
26
+ }
27
+ static identity() {
28
+ // Identity quaternion: (1, 0, 0, 0)
29
+ return new Vec4(V.C(1), V.C(0), V.C(0), V.C(0));
30
+ }
31
+ get magnitude() {
32
+ return V.sqrt(V.add(V.add(V.square(this.w), V.square(this.x)), V.add(V.square(this.y), V.square(this.z))));
33
+ }
34
+ get sqrMagnitude() {
35
+ return V.add(V.add(V.square(this.w), V.square(this.x)), V.add(V.square(this.y), V.square(this.z)));
36
+ }
37
+ get normalized() {
38
+ const mag = this.magnitude;
39
+ return new Vec4(V.div(this.w, mag), V.div(this.x, mag), V.div(this.y, mag), V.div(this.z, mag));
40
+ }
41
+ /**
42
+ * Normalized quaternion with custom analytical gradients.
43
+ * More efficient than autodiff through magnitude and division.
44
+ *
45
+ * Gradient formula: ∂(q/|q|)/∂q = (I - nn^T)/|q| where n = q/|q|
46
+ */
47
+ normalizedCustomGrad() {
48
+ // Forward pass: compute normalized quaternion using .data (no autodiff graph)
49
+ const magSq = this.w.data * this.w.data +
50
+ this.x.data * this.x.data +
51
+ this.y.data * this.y.data +
52
+ this.z.data * this.z.data;
53
+ const mag = Math.sqrt(magSq);
54
+ const nw = this.w.data / mag;
55
+ const nx = this.x.data / mag;
56
+ const ny = this.y.data / mag;
57
+ const nz = this.z.data / mag;
58
+ const invMag = 1.0 / mag;
59
+ // Create output Values with custom backward pass
60
+ // Gradient: ∂(qi/|q|)/∂qj = δij/|q| - qi*qj/|q|³
61
+ const outW = Value.makeNary(nw, [this.w, this.x, this.y, this.z], (out) => () => {
62
+ this.w.grad += out.grad * (1 - nw * nw) * invMag;
63
+ this.x.grad += out.grad * (-nw * nx) * invMag;
64
+ this.y.grad += out.grad * (-nw * ny) * invMag;
65
+ this.z.grad += out.grad * (-nw * nz) * invMag;
66
+ }, 'normalize_w', 'normalize_w');
67
+ const outX = Value.makeNary(nx, [this.w, this.x, this.y, this.z], (out) => () => {
68
+ this.w.grad += out.grad * (-nx * nw) * invMag;
69
+ this.x.grad += out.grad * (1 - nx * nx) * invMag;
70
+ this.y.grad += out.grad * (-nx * ny) * invMag;
71
+ this.z.grad += out.grad * (-nx * nz) * invMag;
72
+ }, 'normalize_x', 'normalize_x');
73
+ const outY = Value.makeNary(ny, [this.w, this.x, this.y, this.z], (out) => () => {
74
+ this.w.grad += out.grad * (-ny * nw) * invMag;
75
+ this.x.grad += out.grad * (-ny * nx) * invMag;
76
+ this.y.grad += out.grad * (1 - ny * ny) * invMag;
77
+ this.z.grad += out.grad * (-ny * nz) * invMag;
78
+ }, 'normalize_y', 'normalize_y');
79
+ const outZ = Value.makeNary(nz, [this.w, this.x, this.y, this.z], (out) => () => {
80
+ this.w.grad += out.grad * (-nz * nw) * invMag;
81
+ this.x.grad += out.grad * (-nz * nx) * invMag;
82
+ this.y.grad += out.grad * (-nz * ny) * invMag;
83
+ this.z.grad += out.grad * (1 - nz * nz) * invMag;
84
+ }, 'normalize_z', 'normalize_z');
85
+ return new Vec4(outW, outX, outY, outZ);
86
+ }
87
+ static dot(a, b) {
88
+ return V.add(V.add(V.mul(a.w, b.w), V.mul(a.x, b.x)), V.add(V.mul(a.y, b.y), V.mul(a.z, b.z)));
89
+ }
90
+ add(other) {
91
+ return new Vec4(V.add(this.w, other.w), V.add(this.x, other.x), V.add(this.y, other.y), V.add(this.z, other.z));
92
+ }
93
+ sub(other) {
94
+ return new Vec4(V.sub(this.w, other.w), V.sub(this.x, other.x), V.sub(this.y, other.y), V.sub(this.z, other.z));
95
+ }
96
+ mul(scalar) {
97
+ return new Vec4(V.mul(this.w, scalar), V.mul(this.x, scalar), V.mul(this.y, scalar), V.mul(this.z, scalar));
98
+ }
99
+ div(scalar) {
100
+ return new Vec4(V.div(this.w, scalar), V.div(this.x, scalar), V.div(this.y, scalar), V.div(this.z, scalar));
101
+ }
102
+ get trainables() {
103
+ return [this.w, this.x, this.y, this.z];
104
+ }
105
+ toString() {
106
+ return `Vec4(${this.w.data}, ${this.x.data}, ${this.y.data}, ${this.z.data})`;
107
+ }
108
+ /**
109
+ * Clone this vector (create new Vec4 with same values but independent graph).
110
+ */
111
+ clone() {
112
+ return new Vec4(new Value(this.w.data), new Value(this.x.data), new Value(this.y.data), new Value(this.z.data));
113
+ }
114
+ /**
115
+ * Create Vec4 from raw data (no gradients).
116
+ */
117
+ static fromData(w, x, y, z) {
118
+ return Vec4.C(w, x, y, z);
119
+ }
120
+ /**
121
+ * Extract raw data as array [w, x, y, z].
122
+ */
123
+ toArray() {
124
+ return [this.w.data, this.x.data, this.y.data, this.z.data];
125
+ }
126
+ }
@@ -0,0 +1,33 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { Value } from '../Value';
3
+ describe('Duplicate Input Gradient Accumulation', () => {
4
+ it('should correctly compute gradients for different inputs (x * y)', () => {
5
+ const x = new Value(2, 'x', true);
6
+ const y = new Value(3, 'y', true);
7
+ const result = x.mul(y);
8
+ result.backward();
9
+ expect(result.data).toBe(6);
10
+ expect(x.grad).toBe(3);
11
+ expect(y.grad).toBe(2);
12
+ });
13
+ it('should correctly compute gradients when same input is used twice (t * t)', () => {
14
+ const t = new Value(2, 't', true);
15
+ const result = t.mul(t);
16
+ result.backward();
17
+ expect(result.data).toBe(4);
18
+ expect(t.grad).toBe(4); // Should be 2*t = 4, not half!
19
+ const expected = 4.0;
20
+ const ratio = t.grad / expected;
21
+ expect(Math.abs(ratio - 1.0)).toBeLessThan(0.01);
22
+ });
23
+ it('should correctly compute gradients for log(1 - t^2) - SAC entropy pattern', () => {
24
+ const t = new Value(0.5, 't', true);
25
+ const tSquared = t.mul(t);
26
+ const oneMinusTSquared = new Value(1, '1').sub(tSquared);
27
+ const result = oneMinusTSquared.log();
28
+ result.backward();
29
+ // Analytical derivative of log(1-t^2) is -2t/(1-t^2)
30
+ const expected = -2 * 0.5 / (1 - 0.25);
31
+ expect(Math.abs(t.grad - expected)).toBeLessThan(0.0001);
32
+ });
33
+ });
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI tool for symbolic gradient generation.
4
+ * Accepts mathematical expressions and outputs gradient computation code.
5
+ */
6
+ interface CliOptions {
7
+ input?: string;
8
+ output?: string;
9
+ wrt?: string[];
10
+ format: 'js' | 'ts' | 'function' | 'inline';
11
+ simplify: boolean;
12
+ functionName?: string;
13
+ help: boolean;
14
+ version: boolean;
15
+ }
16
+ declare function parseArgs(args: string[]): CliOptions;
17
+ declare function extractParameters(input: string): string[];
18
+ declare function main(): void;
19
+ export { main, parseArgs, extractParameters };