diff --git a/lib/model/lagrange.js b/lib/model/lagrange.js index f84a3a18..2e4073f4 100644 --- a/lib/model/lagrange.js +++ b/lib/model/lagrange.js @@ -55,10 +55,16 @@ export default class LagrangeInterpolation { const w = x.map((d, j) => 1 / x.reduce((p, v, i) => (i === j ? p : p * (d - v)), 1)) if (this._w_type === 1) { return target.map(t => { - const l = x.reduce((p, k) => p * (t - k), 1) - return x.reduce((s, d, j) => { - return s + (y[j] * l * w[j]) / (t - d + 1.0e-8) - }, 0) + let l = 1 + let v = 0 + for (let i = 0; i < x.length; i++) { + if (t === x[i]) { + return y[i] + } + l *= t - x[i] + v += (y[i] * w[i]) / (t - x[i]) + } + return l * v }) } else { return target.map(t => { diff --git a/tests/lib/model/lagrange.test.js b/tests/lib/model/lagrange.test.js index 01c379f2..5237e443 100644 --- a/tests/lib/model/lagrange.test.js +++ b/tests/lib/model/lagrange.test.js @@ -23,3 +23,25 @@ test.each([undefined, '', 'weighted', 'newton'])('interpolation %s', { retry: 3 const err = rmse(y0, x0.map(Math.sin)) expect(err).toBeLessThan(0.1) }) + +test('interpolation w type 1', () => { + const model = new LagrangeInterpolation() + model._w_type = 1 + const x = Matrix.random(20, 1, -2, 2).value + const t = [] + for (let i = 0; i < x.length; i++) { + t[i] = Math.sin(x[i]) + } + model.fit(x, t) + + const y = model.predict(x) + expect(y).toHaveLength(x.length) + for (let i = 0; i < y.length; i++) { + expect(y[i]).toBeCloseTo(t[i]) + } + + const x0 = Matrix.random(100, 1, -2, 2).value + const y0 = model.predict(x0) + const err = rmse(y0, x0.map(Math.sin)) + expect(err).toBeLessThan(0.1) +})