UNPKG

1.66 kBJavaScriptView Raw
1import {abs, epsilon, epsilon2} from "./math.js";
2
3// Approximate Newton-Raphson
4// Solve f(x) = y, start from x
5export function solve(f, y, x) {
6 var steps = 100, delta, f0, f1;
7 x = x === undefined ? 0 : +x;
8 y = +y;
9 do {
10 f0 = f(x);
11 f1 = f(x + epsilon);
12 if (f0 === f1) f1 = f0 + epsilon;
13 x -= delta = (-1 * epsilon * (f0 - y)) / (f0 - f1);
14 } while (steps-- > 0 && abs(delta) > epsilon);
15 return steps < 0 ? NaN : x;
16}
17
18// Approximate Newton-Raphson in 2D
19// Solve f(a,b) = [x,y]
20export function solve2d(f, MAX_ITERATIONS = 40, eps = epsilon2) {
21 return function(x, y, a = 0, b = 0) {
22 var err2, da, db;
23 for (var i = 0; i < MAX_ITERATIONS; i++) {
24 var p = f(a, b),
25 // diffs
26 tx = p[0] - x,
27 ty = p[1] - y;
28 if (abs(tx) < eps && abs(ty) < eps) break; // we're there!
29
30 // backtrack if we overshot
31 var h = tx * tx + ty * ty;
32 if (h > err2) {
33 a -= da /= 2;
34 b -= db /= 2;
35 continue;
36 }
37 err2 = h;
38
39 // partial derivatives
40 var ea = (a > 0 ? -1 : 1) * eps,
41 eb = (b > 0 ? -1 : 1) * eps,
42 pa = f(a + ea, b),
43 pb = f(a, b + eb),
44 dxa = (pa[0] - p[0]) / ea,
45 dya = (pa[1] - p[1]) / ea,
46 dxb = (pb[0] - p[0]) / eb,
47 dyb = (pb[1] - p[1]) / eb,
48 // determinant
49 D = dyb * dxa - dya * dxb,
50 // newton step — or half-step for small D
51 l = (abs(D) < 0.5 ? 0.5 : 1) / D;
52 da = (ty * dxb - tx * dyb) * l;
53 db = (tx * dya - ty * dxa) * l;
54 a += da;
55 b += db;
56 if (abs(da) < eps && abs(db) < eps) break; // we're crawling
57 }
58 return [a, b];
59 };
60}
\No newline at end of file