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.
- package/README.md +127 -2
- package/dist/CompiledFunctions.d.ts +111 -0
- package/dist/CompiledFunctions.js +268 -0
- package/dist/CompiledResiduals.d.ts +74 -0
- package/dist/CompiledResiduals.js +94 -0
- package/dist/EigenvalueHelpers.d.ts +14 -0
- package/dist/EigenvalueHelpers.js +93 -0
- package/dist/Geometry.d.ts +131 -0
- package/dist/Geometry.js +213 -0
- package/dist/GraphBuilder.d.ts +64 -0
- package/dist/GraphBuilder.js +237 -0
- package/dist/GraphCanonicalizerNoSort.d.ts +20 -0
- package/dist/GraphCanonicalizerNoSort.js +190 -0
- package/dist/GraphHashCanonicalizer.d.ts +46 -0
- package/dist/GraphHashCanonicalizer.js +220 -0
- package/dist/GraphSignature.d.ts +7 -0
- package/dist/GraphSignature.js +7 -0
- package/dist/KernelPool.d.ts +55 -0
- package/dist/KernelPool.js +124 -0
- package/dist/LBFGS.d.ts +84 -0
- package/dist/LBFGS.js +313 -0
- package/dist/LinearSolver.d.ts +69 -0
- package/dist/LinearSolver.js +213 -0
- package/dist/Losses.d.ts +9 -0
- package/dist/Losses.js +42 -37
- package/dist/Matrix3x3.d.ts +50 -0
- package/dist/Matrix3x3.js +146 -0
- package/dist/NonlinearLeastSquares.d.ts +33 -0
- package/dist/NonlinearLeastSquares.js +252 -0
- package/dist/Optimizers.d.ts +70 -14
- package/dist/Optimizers.js +42 -19
- package/dist/V.d.ts +0 -0
- package/dist/V.js +0 -0
- package/dist/Value.d.ts +84 -2
- package/dist/Value.js +296 -58
- package/dist/ValueActivation.js +10 -14
- package/dist/ValueArithmetic.d.ts +1 -0
- package/dist/ValueArithmetic.js +58 -50
- package/dist/ValueComparison.js +9 -13
- package/dist/ValueRegistry.d.ts +38 -0
- package/dist/ValueRegistry.js +88 -0
- package/dist/ValueTrig.js +14 -18
- package/dist/Vec2.d.ts +45 -0
- package/dist/Vec2.js +93 -0
- package/dist/Vec3.d.ts +78 -0
- package/dist/Vec3.js +169 -0
- package/dist/Vec4.d.ts +45 -0
- package/dist/Vec4.js +126 -0
- package/dist/__tests__/duplicate-inputs.test.js +33 -0
- package/dist/cli/gradient-gen.d.ts +19 -0
- package/dist/cli/gradient-gen.js +264 -0
- package/dist/compileIndirectKernel.d.ts +24 -0
- package/dist/compileIndirectKernel.js +148 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +20 -0
- package/dist/scalar-autograd.d.ts +1157 -0
- package/dist/symbolic/AST.d.ts +113 -0
- package/dist/symbolic/AST.js +128 -0
- package/dist/symbolic/CodeGen.d.ts +35 -0
- package/dist/symbolic/CodeGen.js +280 -0
- package/dist/symbolic/Parser.d.ts +64 -0
- package/dist/symbolic/Parser.js +329 -0
- package/dist/symbolic/Simplify.d.ts +10 -0
- package/dist/symbolic/Simplify.js +244 -0
- package/dist/symbolic/SymbolicDiff.d.ts +35 -0
- package/dist/symbolic/SymbolicDiff.js +339 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/package.json +29 -5
- package/dist/Losses.spec.js +0 -54
- package/dist/Optimizers.edge-cases.spec.d.ts +0 -1
- package/dist/Optimizers.edge-cases.spec.js +0 -29
- package/dist/Optimizers.spec.d.ts +0 -1
- package/dist/Optimizers.spec.js +0 -56
- package/dist/Value.edge-cases.spec.d.ts +0 -1
- package/dist/Value.edge-cases.spec.js +0 -54
- package/dist/Value.grad-flow.spec.d.ts +0 -1
- package/dist/Value.grad-flow.spec.js +0 -24
- package/dist/Value.losses-edge-cases.spec.d.ts +0 -1
- package/dist/Value.losses-edge-cases.spec.js +0 -30
- package/dist/Value.memory.spec.d.ts +0 -1
- package/dist/Value.memory.spec.js +0 -23
- package/dist/Value.nn.spec.d.ts +0 -1
- package/dist/Value.nn.spec.js +0 -111
- package/dist/Value.spec.d.ts +0 -1
- package/dist/Value.spec.js +0 -245
- /package/dist/{Losses.spec.d.ts → __tests__/duplicate-inputs.test.d.ts} +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External helper functions for eigenvalue computation in compiled code.
|
|
3
|
+
* These are called from generated JavaScript to avoid inlining huge formulas.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Compute smallest eigenvalue of 3x3 symmetric matrix.
|
|
7
|
+
* Uses Cardano's formula for cubic equation.
|
|
8
|
+
*/
|
|
9
|
+
export declare function computeSmallestEigenvalue(c00: number, c01: number, c02: number, c11: number, c12: number, c22: number): number;
|
|
10
|
+
/**
|
|
11
|
+
* Apply eigenvalue gradients using analytical formula.
|
|
12
|
+
* Computes eigenvector and updates input gradients with ∂λ/∂C_ij = v_i * v_j
|
|
13
|
+
*/
|
|
14
|
+
export declare function applyEigenvalueGradients(outGrad: number, c00: number, c01: number, c02: number, c11: number, c12: number, c22: number, g00: number, g01: number, g02: number, g11: number, g12: number, g22: number): [number, number, number, number, number, number];
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External helper functions for eigenvalue computation in compiled code.
|
|
3
|
+
* These are called from generated JavaScript to avoid inlining huge formulas.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Compute smallest eigenvalue of 3x3 symmetric matrix.
|
|
7
|
+
* Uses Cardano's formula for cubic equation.
|
|
8
|
+
*/
|
|
9
|
+
export function computeSmallestEigenvalue(c00, c01, c02, c11, c12, c22) {
|
|
10
|
+
const tr = c00 + c11 + c22;
|
|
11
|
+
const shift = tr / 3;
|
|
12
|
+
const b00 = c00 - shift;
|
|
13
|
+
const b11 = c11 - shift;
|
|
14
|
+
const b22 = c22 - shift;
|
|
15
|
+
const q = 0.5 * (b00 * b00 + b11 * b11 + b22 * b22 + 2 * c01 * c01 + 2 * c02 * c02 + 2 * c12 * c12);
|
|
16
|
+
const p = Math.sqrt((q + 1e-20) / 3);
|
|
17
|
+
const invP = 1 / (p + 1e-12);
|
|
18
|
+
const d00 = b00 * invP;
|
|
19
|
+
const d01 = c01 * invP;
|
|
20
|
+
const d02 = c02 * invP;
|
|
21
|
+
const d11 = b11 * invP;
|
|
22
|
+
const d12 = c12 * invP;
|
|
23
|
+
const d22 = b22 * invP;
|
|
24
|
+
const det = d00 * (d11 * d22 - d12 * d12) + d01 * (d12 * d02 - d01 * d22) + d02 * (d01 * d12 - d11 * d02);
|
|
25
|
+
const r = Math.max(-0.99999, Math.min(det / 2, 0.99999));
|
|
26
|
+
const theta = Math.acos(r);
|
|
27
|
+
const angle2 = theta / 3 + 2 * 2.0943951023931953;
|
|
28
|
+
return shift + 2 * p * Math.cos(angle2);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Apply eigenvalue gradients using analytical formula.
|
|
32
|
+
* Computes eigenvector and updates input gradients with ∂λ/∂C_ij = v_i * v_j
|
|
33
|
+
*/
|
|
34
|
+
export function applyEigenvalueGradients(outGrad, c00, c01, c02, c11, c12, c22, g00, g01, g02, g11, g12, g22) {
|
|
35
|
+
const lambda = computeSmallestEigenvalue(c00, c01, c02, c11, c12, c22);
|
|
36
|
+
const a00 = c00 - lambda;
|
|
37
|
+
const a11 = c11 - lambda;
|
|
38
|
+
const a22 = c22 - lambda;
|
|
39
|
+
const row0_x = a00, row0_y = c01, row0_z = c02;
|
|
40
|
+
const row1_x = c01, row1_y = a11, row1_z = c12;
|
|
41
|
+
const row2_x = c02, row2_y = c12, row2_z = a22;
|
|
42
|
+
const cross0_x = row0_y * row1_z - row0_z * row1_y;
|
|
43
|
+
const cross0_y = row0_z * row1_x - row0_x * row1_z;
|
|
44
|
+
const cross0_z = row0_x * row1_y - row0_y * row1_x;
|
|
45
|
+
const cross1_x = row0_y * row2_z - row0_z * row2_y;
|
|
46
|
+
const cross1_y = row0_z * row2_x - row0_x * row2_z;
|
|
47
|
+
const cross1_z = row0_x * row2_y - row0_y * row2_x;
|
|
48
|
+
const cross2_x = row1_y * row2_z - row1_z * row2_y;
|
|
49
|
+
const cross2_y = row1_z * row2_x - row1_x * row2_z;
|
|
50
|
+
const cross2_z = row1_x * row2_y - row1_y * row2_x;
|
|
51
|
+
const mag0 = Math.sqrt(cross0_x * cross0_x + cross0_y * cross0_y + cross0_z * cross0_z);
|
|
52
|
+
const mag1 = Math.sqrt(cross1_x * cross1_x + cross1_y * cross1_y + cross1_z * cross1_z);
|
|
53
|
+
const mag2 = Math.sqrt(cross2_x * cross2_x + cross2_y * cross2_y + cross2_z * cross2_z);
|
|
54
|
+
let bestMag = mag0;
|
|
55
|
+
let vx = cross0_x, vy = cross0_y, vz = cross0_z;
|
|
56
|
+
if (mag1 > bestMag) {
|
|
57
|
+
bestMag = mag1;
|
|
58
|
+
vx = cross1_x;
|
|
59
|
+
vy = cross1_y;
|
|
60
|
+
vz = cross1_z;
|
|
61
|
+
}
|
|
62
|
+
if (mag2 > bestMag) {
|
|
63
|
+
bestMag = mag2;
|
|
64
|
+
vx = cross2_x;
|
|
65
|
+
vy = cross2_y;
|
|
66
|
+
vz = cross2_z;
|
|
67
|
+
}
|
|
68
|
+
if (bestMag < 1e-12) {
|
|
69
|
+
vx = 1;
|
|
70
|
+
vy = 0;
|
|
71
|
+
vz = 0;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
vx /= bestMag;
|
|
75
|
+
vy /= bestMag;
|
|
76
|
+
vz /= bestMag;
|
|
77
|
+
}
|
|
78
|
+
return [
|
|
79
|
+
g00 + outGrad * vx * vx,
|
|
80
|
+
g01 + outGrad * 2 * vx * vy,
|
|
81
|
+
g02 + outGrad * 2 * vx * vz,
|
|
82
|
+
g11 + outGrad * vy * vy,
|
|
83
|
+
g12 + outGrad * 2 * vy * vz,
|
|
84
|
+
g22 + outGrad * vz * vz
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
// Make available globally for compiled code
|
|
88
|
+
if (typeof window !== 'undefined') {
|
|
89
|
+
window.__eigenHelpers = {
|
|
90
|
+
computeSmallestEigenvalue,
|
|
91
|
+
applyEigenvalueGradients
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Vec3 } from './Vec3';
|
|
2
|
+
import { Value } from './Value';
|
|
3
|
+
/**
|
|
4
|
+
* Geometric utility functions for triangle mesh operations.
|
|
5
|
+
* All methods are differentiable and support automatic gradient computation.
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
export declare class Geometry {
|
|
9
|
+
/**
|
|
10
|
+
* Compute the normal of a triangle defined by three vertices.
|
|
11
|
+
* Uses right-hand rule: normal points in direction of (b-a) × (c-a).
|
|
12
|
+
* Returns a UNIT normal vector.
|
|
13
|
+
*
|
|
14
|
+
* @param a - First vertex
|
|
15
|
+
* @param b - Second vertex
|
|
16
|
+
* @param c - Third vertex
|
|
17
|
+
* @returns Unit normal vector
|
|
18
|
+
*/
|
|
19
|
+
static triangleNormal(a: Vec3, b: Vec3, c: Vec3): Vec3;
|
|
20
|
+
/**
|
|
21
|
+
* Compute the area of a triangle defined by three vertices.
|
|
22
|
+
* Uses the cross product formula: Area = 0.5 * ||(b-a) × (c-a)||
|
|
23
|
+
*
|
|
24
|
+
* @param a - First vertex
|
|
25
|
+
* @param b - Second vertex
|
|
26
|
+
* @param c - Third vertex
|
|
27
|
+
* @returns Triangle area
|
|
28
|
+
*/
|
|
29
|
+
static triangleArea(a: Vec3, b: Vec3, c: Vec3): Value;
|
|
30
|
+
/**
|
|
31
|
+
* Compute the interior angle at vertex b in triangle abc.
|
|
32
|
+
* Returns angle in radians, range [0, π].
|
|
33
|
+
*
|
|
34
|
+
* Formula: angle = acos(dot(normalize(a-b), normalize(c-b)))
|
|
35
|
+
*
|
|
36
|
+
* @param a - First neighboring vertex
|
|
37
|
+
* @param b - Vertex where angle is measured
|
|
38
|
+
* @param c - Second neighboring vertex
|
|
39
|
+
* @returns Interior angle in radians
|
|
40
|
+
*/
|
|
41
|
+
static interiorAngle(a: Vec3, b: Vec3, c: Vec3): Value;
|
|
42
|
+
/**
|
|
43
|
+
* Compute the angle defect at a vertex.
|
|
44
|
+
* Angle defect = 2π - sum of interior angles around the vertex.
|
|
45
|
+
* For flat regions, angle defect = 0.
|
|
46
|
+
* For positive Gaussian curvature (sphere-like), angle defect > 0.
|
|
47
|
+
* For negative Gaussian curvature (saddle-like), angle defect < 0.
|
|
48
|
+
*
|
|
49
|
+
* @param center - The vertex at which to compute angle defect
|
|
50
|
+
* @param neighbors - Ordered list of neighboring vertices (CCW or CW)
|
|
51
|
+
* @returns Angle defect in radians
|
|
52
|
+
*/
|
|
53
|
+
static angleDefect(center: Vec3, neighbors: Vec3[]): Value;
|
|
54
|
+
/**
|
|
55
|
+
* Compute the centroid (center of mass) of a set of points.
|
|
56
|
+
*
|
|
57
|
+
* @param points - Array of points
|
|
58
|
+
* @returns Centroid
|
|
59
|
+
*/
|
|
60
|
+
static centroid(points: Vec3[]): Vec3;
|
|
61
|
+
/**
|
|
62
|
+
* Compute area-weighted normal at a vertex.
|
|
63
|
+
* This is the sum of face normals weighted by face areas,
|
|
64
|
+
* then normalized. Provides a smooth approximation of the
|
|
65
|
+
* surface normal at a vertex.
|
|
66
|
+
*
|
|
67
|
+
* @param center - The vertex
|
|
68
|
+
* @param triangles - Array of triangles as [Vec3, Vec3, Vec3] where center is one of the vertices
|
|
69
|
+
* @returns Area-weighted unit normal
|
|
70
|
+
*/
|
|
71
|
+
static vertexNormal(center: Vec3, triangles: [Vec3, Vec3, Vec3][]): Vec3;
|
|
72
|
+
/**
|
|
73
|
+
* Project point onto a plane defined by a point and normal.
|
|
74
|
+
*
|
|
75
|
+
* @param point - Point to project
|
|
76
|
+
* @param planePoint - A point on the plane
|
|
77
|
+
* @param planeNormal - Unit normal of the plane
|
|
78
|
+
* @returns Projected point
|
|
79
|
+
*/
|
|
80
|
+
static projectToPlane(point: Vec3, planePoint: Vec3, planeNormal: Vec3): Vec3;
|
|
81
|
+
/**
|
|
82
|
+
* Compute signed distance from point to plane.
|
|
83
|
+
* Positive if point is on the side the normal points to.
|
|
84
|
+
*
|
|
85
|
+
* @param point - Point to measure
|
|
86
|
+
* @param planePoint - A point on the plane
|
|
87
|
+
* @param planeNormal - Unit normal of the plane
|
|
88
|
+
* @returns Signed distance
|
|
89
|
+
*/
|
|
90
|
+
static distanceToPlane(point: Vec3, planePoint: Vec3, planeNormal: Vec3): Value;
|
|
91
|
+
/**
|
|
92
|
+
* Check if a set of normals are coplanar (lie in a common plane).
|
|
93
|
+
* Returns a measure of non-coplanarity (0 = perfectly coplanar).
|
|
94
|
+
* Uses the smallest eigenvalue of the normal covariance matrix.
|
|
95
|
+
*
|
|
96
|
+
* This is a simplified version - the full implementation would
|
|
97
|
+
* compute eigenvalues. For now, returns sum of cross products.
|
|
98
|
+
*
|
|
99
|
+
* @param normals - Array of unit normal vectors
|
|
100
|
+
* @returns Measure of non-coplanarity (0 = coplanar)
|
|
101
|
+
*/
|
|
102
|
+
static normalCoplanarity(normals: Vec3[]): Value;
|
|
103
|
+
/**
|
|
104
|
+
* Compute the dihedral angle between two triangles sharing an edge.
|
|
105
|
+
* Returns angle in radians, range [0, π].
|
|
106
|
+
* Angle = 0 means triangles are coplanar.
|
|
107
|
+
* Angle = π means triangles fold completely back on themselves.
|
|
108
|
+
*
|
|
109
|
+
* @param n1 - Normal of first triangle
|
|
110
|
+
* @param n2 - Normal of second triangle
|
|
111
|
+
* @returns Dihedral angle in radians
|
|
112
|
+
*/
|
|
113
|
+
static dihedralAngle(n1: Vec3, n2: Vec3): Value;
|
|
114
|
+
/**
|
|
115
|
+
* Compute the average of multiple vectors.
|
|
116
|
+
*
|
|
117
|
+
* @param vectors - Array of vectors
|
|
118
|
+
* @returns Average vector (not normalized)
|
|
119
|
+
*/
|
|
120
|
+
static average(vectors: Vec3[]): Vec3;
|
|
121
|
+
/**
|
|
122
|
+
* Compute bounding box of a set of points.
|
|
123
|
+
*
|
|
124
|
+
* @param points - Array of points
|
|
125
|
+
* @returns Object with min and max corners
|
|
126
|
+
*/
|
|
127
|
+
static boundingBox(points: Vec3[]): {
|
|
128
|
+
min: Vec3;
|
|
129
|
+
max: Vec3;
|
|
130
|
+
};
|
|
131
|
+
}
|
package/dist/Geometry.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { Vec3 } from './Vec3';
|
|
2
|
+
import { V } from './V';
|
|
3
|
+
/**
|
|
4
|
+
* Geometric utility functions for triangle mesh operations.
|
|
5
|
+
* All methods are differentiable and support automatic gradient computation.
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
export class Geometry {
|
|
9
|
+
/**
|
|
10
|
+
* Compute the normal of a triangle defined by three vertices.
|
|
11
|
+
* Uses right-hand rule: normal points in direction of (b-a) × (c-a).
|
|
12
|
+
* Returns a UNIT normal vector.
|
|
13
|
+
*
|
|
14
|
+
* @param a - First vertex
|
|
15
|
+
* @param b - Second vertex
|
|
16
|
+
* @param c - Third vertex
|
|
17
|
+
* @returns Unit normal vector
|
|
18
|
+
*/
|
|
19
|
+
static triangleNormal(a, b, c) {
|
|
20
|
+
const edge1 = b.sub(a);
|
|
21
|
+
const edge2 = c.sub(a);
|
|
22
|
+
const cross = Vec3.cross(edge1, edge2);
|
|
23
|
+
return cross.normalized;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Compute the area of a triangle defined by three vertices.
|
|
27
|
+
* Uses the cross product formula: Area = 0.5 * ||(b-a) × (c-a)||
|
|
28
|
+
*
|
|
29
|
+
* @param a - First vertex
|
|
30
|
+
* @param b - Second vertex
|
|
31
|
+
* @param c - Third vertex
|
|
32
|
+
* @returns Triangle area
|
|
33
|
+
*/
|
|
34
|
+
static triangleArea(a, b, c) {
|
|
35
|
+
const edge1 = b.sub(a);
|
|
36
|
+
const edge2 = c.sub(a);
|
|
37
|
+
const cross = Vec3.cross(edge1, edge2);
|
|
38
|
+
return V.mul(0.5, cross.magnitude);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Compute the interior angle at vertex b in triangle abc.
|
|
42
|
+
* Returns angle in radians, range [0, π].
|
|
43
|
+
*
|
|
44
|
+
* Formula: angle = acos(dot(normalize(a-b), normalize(c-b)))
|
|
45
|
+
*
|
|
46
|
+
* @param a - First neighboring vertex
|
|
47
|
+
* @param b - Vertex where angle is measured
|
|
48
|
+
* @param c - Second neighboring vertex
|
|
49
|
+
* @returns Interior angle in radians
|
|
50
|
+
*/
|
|
51
|
+
static interiorAngle(a, b, c) {
|
|
52
|
+
const ba = a.sub(b).normalized;
|
|
53
|
+
const bc = c.sub(b).normalized;
|
|
54
|
+
return Vec3.angleBetween(ba, bc);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Compute the angle defect at a vertex.
|
|
58
|
+
* Angle defect = 2π - sum of interior angles around the vertex.
|
|
59
|
+
* For flat regions, angle defect = 0.
|
|
60
|
+
* For positive Gaussian curvature (sphere-like), angle defect > 0.
|
|
61
|
+
* For negative Gaussian curvature (saddle-like), angle defect < 0.
|
|
62
|
+
*
|
|
63
|
+
* @param center - The vertex at which to compute angle defect
|
|
64
|
+
* @param neighbors - Ordered list of neighboring vertices (CCW or CW)
|
|
65
|
+
* @returns Angle defect in radians
|
|
66
|
+
*/
|
|
67
|
+
static angleDefect(center, neighbors) {
|
|
68
|
+
let angleSum = V.C(0);
|
|
69
|
+
const n = neighbors.length;
|
|
70
|
+
for (let i = 0; i < n; i++) {
|
|
71
|
+
const prev = neighbors[i];
|
|
72
|
+
const next = neighbors[(i + 1) % n];
|
|
73
|
+
const angle = Geometry.interiorAngle(prev, center, next);
|
|
74
|
+
angleSum = V.add(angleSum, angle);
|
|
75
|
+
}
|
|
76
|
+
return V.sub(2 * Math.PI, angleSum);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Compute the centroid (center of mass) of a set of points.
|
|
80
|
+
*
|
|
81
|
+
* @param points - Array of points
|
|
82
|
+
* @returns Centroid
|
|
83
|
+
*/
|
|
84
|
+
static centroid(points) {
|
|
85
|
+
if (points.length === 0) {
|
|
86
|
+
return Vec3.zero();
|
|
87
|
+
}
|
|
88
|
+
let sum = Vec3.zero();
|
|
89
|
+
for (const p of points) {
|
|
90
|
+
sum = sum.add(p);
|
|
91
|
+
}
|
|
92
|
+
return sum.div(points.length);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Compute area-weighted normal at a vertex.
|
|
96
|
+
* This is the sum of face normals weighted by face areas,
|
|
97
|
+
* then normalized. Provides a smooth approximation of the
|
|
98
|
+
* surface normal at a vertex.
|
|
99
|
+
*
|
|
100
|
+
* @param center - The vertex
|
|
101
|
+
* @param triangles - Array of triangles as [Vec3, Vec3, Vec3] where center is one of the vertices
|
|
102
|
+
* @returns Area-weighted unit normal
|
|
103
|
+
*/
|
|
104
|
+
static vertexNormal(center, triangles) {
|
|
105
|
+
let weightedSum = Vec3.zero();
|
|
106
|
+
for (const [a, b, c] of triangles) {
|
|
107
|
+
const normal = Geometry.triangleNormal(a, b, c);
|
|
108
|
+
const area = Geometry.triangleArea(a, b, c);
|
|
109
|
+
weightedSum = weightedSum.add(normal.mul(area));
|
|
110
|
+
}
|
|
111
|
+
return weightedSum.normalized;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Project point onto a plane defined by a point and normal.
|
|
115
|
+
*
|
|
116
|
+
* @param point - Point to project
|
|
117
|
+
* @param planePoint - A point on the plane
|
|
118
|
+
* @param planeNormal - Unit normal of the plane
|
|
119
|
+
* @returns Projected point
|
|
120
|
+
*/
|
|
121
|
+
static projectToPlane(point, planePoint, planeNormal) {
|
|
122
|
+
const toPoint = point.sub(planePoint);
|
|
123
|
+
const distance = Vec3.dot(toPoint, planeNormal);
|
|
124
|
+
const offset = planeNormal.mul(distance);
|
|
125
|
+
return point.sub(offset);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Compute signed distance from point to plane.
|
|
129
|
+
* Positive if point is on the side the normal points to.
|
|
130
|
+
*
|
|
131
|
+
* @param point - Point to measure
|
|
132
|
+
* @param planePoint - A point on the plane
|
|
133
|
+
* @param planeNormal - Unit normal of the plane
|
|
134
|
+
* @returns Signed distance
|
|
135
|
+
*/
|
|
136
|
+
static distanceToPlane(point, planePoint, planeNormal) {
|
|
137
|
+
const toPoint = point.sub(planePoint);
|
|
138
|
+
return Vec3.dot(toPoint, planeNormal);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Check if a set of normals are coplanar (lie in a common plane).
|
|
142
|
+
* Returns a measure of non-coplanarity (0 = perfectly coplanar).
|
|
143
|
+
* Uses the smallest eigenvalue of the normal covariance matrix.
|
|
144
|
+
*
|
|
145
|
+
* This is a simplified version - the full implementation would
|
|
146
|
+
* compute eigenvalues. For now, returns sum of cross products.
|
|
147
|
+
*
|
|
148
|
+
* @param normals - Array of unit normal vectors
|
|
149
|
+
* @returns Measure of non-coplanarity (0 = coplanar)
|
|
150
|
+
*/
|
|
151
|
+
static normalCoplanarity(normals) {
|
|
152
|
+
if (normals.length < 2)
|
|
153
|
+
return V.C(0);
|
|
154
|
+
// Simple measure: sum of squared cross products between all pairs
|
|
155
|
+
// If all normals are coplanar, all cross products lie along the same axis
|
|
156
|
+
let deviation = V.C(0);
|
|
157
|
+
for (let i = 0; i < normals.length; i++) {
|
|
158
|
+
for (let j = i + 1; j < normals.length; j++) {
|
|
159
|
+
const cross = Vec3.cross(normals[i], normals[j]);
|
|
160
|
+
deviation = V.add(deviation, cross.sqrMagnitude);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return deviation;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Compute the dihedral angle between two triangles sharing an edge.
|
|
167
|
+
* Returns angle in radians, range [0, π].
|
|
168
|
+
* Angle = 0 means triangles are coplanar.
|
|
169
|
+
* Angle = π means triangles fold completely back on themselves.
|
|
170
|
+
*
|
|
171
|
+
* @param n1 - Normal of first triangle
|
|
172
|
+
* @param n2 - Normal of second triangle
|
|
173
|
+
* @returns Dihedral angle in radians
|
|
174
|
+
*/
|
|
175
|
+
static dihedralAngle(n1, n2) {
|
|
176
|
+
const dotProd = Vec3.dot(n1, n2);
|
|
177
|
+
const clampedDot = V.clamp(dotProd, -1, 1);
|
|
178
|
+
return V.acos(clampedDot);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Compute the average of multiple vectors.
|
|
182
|
+
*
|
|
183
|
+
* @param vectors - Array of vectors
|
|
184
|
+
* @returns Average vector (not normalized)
|
|
185
|
+
*/
|
|
186
|
+
static average(vectors) {
|
|
187
|
+
if (vectors.length === 0)
|
|
188
|
+
return Vec3.zero();
|
|
189
|
+
let sum = Vec3.zero();
|
|
190
|
+
for (const v of vectors) {
|
|
191
|
+
sum = sum.add(v);
|
|
192
|
+
}
|
|
193
|
+
return sum.div(vectors.length);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Compute bounding box of a set of points.
|
|
197
|
+
*
|
|
198
|
+
* @param points - Array of points
|
|
199
|
+
* @returns Object with min and max corners
|
|
200
|
+
*/
|
|
201
|
+
static boundingBox(points) {
|
|
202
|
+
if (points.length === 0) {
|
|
203
|
+
return { min: Vec3.zero(), max: Vec3.zero() };
|
|
204
|
+
}
|
|
205
|
+
let min = points[0].clone();
|
|
206
|
+
let max = points[0].clone();
|
|
207
|
+
for (let i = 1; i < points.length; i++) {
|
|
208
|
+
min = Vec3.min(min, points[i]);
|
|
209
|
+
max = Vec3.max(max, points[i]);
|
|
210
|
+
}
|
|
211
|
+
return { min, max };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Value } from './Value';
|
|
2
|
+
/**
|
|
3
|
+
* Graph signature with hash and input mapping
|
|
4
|
+
*/
|
|
5
|
+
export interface GraphSignature {
|
|
6
|
+
/** Hash string for kernel matching */
|
|
7
|
+
hash: string;
|
|
8
|
+
/** Ordered list of leaf Value objects (params first, then constants) */
|
|
9
|
+
leaves: Value[];
|
|
10
|
+
/** Map from Value to index in leaves array */
|
|
11
|
+
leafIndexMap: Map<Value, number>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Incremental graph builder that tracks structure during construction.
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const builder = new GraphBuilder(knownParams);
|
|
19
|
+
* const result = builder.build(() => {
|
|
20
|
+
* const a = V.add(params[0], params[1]);
|
|
21
|
+
* const b = V.mul(a, V.C(2));
|
|
22
|
+
* return b;
|
|
23
|
+
* });
|
|
24
|
+
* // result.signature.hash - for kernel lookup
|
|
25
|
+
* // result.signature.leaves - for index mapping at execution time
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare class GraphBuilder {
|
|
29
|
+
private leaves;
|
|
30
|
+
private leafIndexMap;
|
|
31
|
+
private knownParams;
|
|
32
|
+
private operations;
|
|
33
|
+
/**
|
|
34
|
+
* Create a new graph builder.
|
|
35
|
+
* @param knownParams - Parameters that are known upfront (will be indexed first)
|
|
36
|
+
*/
|
|
37
|
+
constructor(knownParams?: Value[]);
|
|
38
|
+
/**
|
|
39
|
+
* Register a leaf Value and return its index.
|
|
40
|
+
* If already registered, returns existing index.
|
|
41
|
+
* New parameters are added dynamically.
|
|
42
|
+
*/
|
|
43
|
+
private registerLeaf;
|
|
44
|
+
/**
|
|
45
|
+
* Record an operation during graph building.
|
|
46
|
+
* Called automatically by Value.make() when in tracked context.
|
|
47
|
+
* @internal
|
|
48
|
+
*/
|
|
49
|
+
recordOp(value: Value): void;
|
|
50
|
+
/**
|
|
51
|
+
* Build a graph in tracked context and return output + signature.
|
|
52
|
+
*
|
|
53
|
+
* @param fn - Function that builds and returns the output Value
|
|
54
|
+
* @returns Output value and graph signature
|
|
55
|
+
*/
|
|
56
|
+
build(fn: () => Value): {
|
|
57
|
+
output: Value;
|
|
58
|
+
signature: GraphSignature;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Get current signature without finalizing (for debugging)
|
|
62
|
+
*/
|
|
63
|
+
getCurrentSignature(): Partial<GraphSignature>;
|
|
64
|
+
}
|