/ proof-of-concept / toy-instruments
Sign in
proof-of-concept / toy-instruments
toy-instruments / test / hinge.test.ts
38 lines · 1.6 KBCodeBlameHistory
2import { hingeAngleGrad } from '../src/sim/hinge';
4// random bent configuration around an edge along x
5function config(seed: number): Float64Array {
6 let s = seed;
7 const r = () => ((s = (s * 16807) % 2147483647) / 2147483647 - 0.5) * 0.3;
8 // w0, w1, e0, e1
9 return Float64Array.from([0.5 + r(), 0.8 + r(), r(), 0.4 + r(), -0.7 + r(), 0.3 + r(), r(), r(), r(), 1 + r(), r(), r()]);
12describe('hinge', () => {
13 it('angle is zero when flat and matches a fold of known angle', () => {
14 const flat = Float64Array.from([0.5, 0, 1, 0.5, 0, -1, 0, 0, 0, 1, 0, 0]);
15 expect(hingeAngleGrad(flat, 0, 1, 2, 3)).toBeCloseTo(0, 12);
16 const a = 0.3; // fold w1 down by angle a about the x axis
17 const fold = Float64Array.from([0.5, 0, 1, 0.5, -Math.sin(a), -Math.cos(a), 0, 0, 0, 1, 0, 0]);
18 expect(Math.abs(hingeAngleGrad(fold, 0, 1, 2, 3))).toBeCloseTo(a, 12);
19 });
20 it('gradient matches finite differences', () => {
21 for (let seed = 1; seed <= 5; seed++) {
22 const X = config(seed * 7919);
23 const out = new Float64Array(13);
24 hingeAngleGrad(X, 0, 1, 2, 3, out);
25 const order = [0, 1, 2, 3]; // node k's gradient is at out[1 + 3k]
26 const h = 1e-6;
27 for (const node of order)
28 for (let c = 0; c < 3; c++) {
29 const Xp = X.slice();
30 const Xm = X.slice();
31 Xp[3 * node + c] += h;
32 Xm[3 * node + c] -= h;
33 const fd = (hingeAngleGrad(Xp, 0, 1, 2, 3) - hingeAngleGrad(Xm, 0, 1, 2, 3)) / (2 * h);
34 expect(out[1 + 3 * node + c]).toBeCloseTo(fd, 6);
35 }
36 }
37 });
38});
↑↓ move↵openescclose