diff --git a/js/view/gan.js b/js/view/gan.js index 465ea725..e742e229 100644 --- a/js/view/gan.js +++ b/js/view/gan.js @@ -123,7 +123,14 @@ export default function (platform) { { name: 'dis_rate', title: 'D', value: 0.5 }, ]) { const grd = ganRatesDiv.div() - rateElms[v.name] = grd.input.number({ label: v.title, name: v.name, min: 0, max: 100, step: 0.01, value: v.value }) + rateElms[v.name] = grd.input.number({ + label: v.title, + name: v.name, + min: 0, + max: 100, + step: 0.01, + value: v.value, + }) } const batch = controller.input.number({ label: ' Batch size ', min: 1, max: 100, value: 10 }) let threshold = null diff --git a/tests/lib/model/categorical_naive_bayes.test.js b/tests/lib/model/categorical_naive_bayes.test.js index 45bee0d9..4e87da9f 100644 --- a/tests/lib/model/categorical_naive_bayes.test.js +++ b/tests/lib/model/categorical_naive_bayes.test.js @@ -32,3 +32,32 @@ test('predict', () => { const acc = accuracy(y, t) expect(acc).toBeGreaterThan(0.95) }) + +test('predict fit twice', () => { + const model = new CategoricalNaiveBayes() + const x = [['a']] + const t = [] + for (let i = 0; i < x.length; i++) { + t[i] = 'x' + } + + model.fit(x, t) + model.fit(x, t) + + const y = model.predict([['a']]) + expect(y).toEqual(['x']) +}) + +test('predict unknown data label', () => { + const model = new CategoricalNaiveBayes() + const x = [['a']] + const t = [] + for (let i = 0; i < x.length; i++) { + t[i] = 'x' + } + + model.fit(x, t) + + const y = model.predict([['b']]) + expect(y).toEqual([null]) +}) diff --git a/tests/lib/model/catmull_rom.test.js b/tests/lib/model/catmull_rom.test.js index 3d8b529f..debc2495 100644 --- a/tests/lib/model/catmull_rom.test.js +++ b/tests/lib/model/catmull_rom.test.js @@ -27,23 +27,35 @@ test('CatmullRomSplines', () => { expect(err).toBeLessThan(0.1) }) -test('CentripetalCatmullRomSplines', () => { - const model = new CentripetalCatmullRomSplines() - 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) +describe('CentripetalCatmullRomSplines', () => { + test('default', () => { + const model = new CentripetalCatmullRomSplines() + 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) + }) + + test('predict second largest value', () => { + const model = new CentripetalCatmullRomSplines() + const x = [0, 2] + const t = [0, 1] + model.fit(x, t) + + const y = model.predict([1]) + expect(y[0]).toBeCloseTo(0.5) + }) }) diff --git a/tests/lib/model/change_finder.test.js b/tests/lib/model/change_finder.test.js index b7057c35..04eb239d 100644 --- a/tests/lib/model/change_finder.test.js +++ b/tests/lib/model/change_finder.test.js @@ -1,11 +1,22 @@ import Matrix from '../../../lib/util/matrix.js' import ChangeFinder from '../../../lib/model/change_finder.js' -test('anomaly detection', () => { - const model = new ChangeFinder(5) - const n = 50 - const x = Matrix.concat(Matrix.random(n, 1, 0, 1), Matrix.random(n, 1, 10, 11)).value - model.fit(x) - const p = model.predict() - expect(p).toHaveLength(100) +describe('anomaly detection', () => { + test('default', () => { + const model = new ChangeFinder() + const n = 50 + const x = Matrix.concat(Matrix.random(n, 1, 0, 1), Matrix.random(n, 1, 10, 11)).value + model.fit(x) + const p = model.predict() + expect(p).toHaveLength(100) + }) + + test('with params', () => { + const model = new ChangeFinder(5) + const n = 50 + const x = Matrix.concat(Matrix.random(n, 1, 0, 1), Matrix.random(n, 1, 10, 11)).value + model.fit(x) + const p = model.predict() + expect(p).toHaveLength(100) + }) }) diff --git a/tests/lib/model/co_training.test.js b/tests/lib/model/co_training.test.js index f1ac23d2..ea219b2f 100644 --- a/tests/lib/model/co_training.test.js +++ b/tests/lib/model/co_training.test.js @@ -77,3 +77,33 @@ test('semi-classifier', () => { const acc = accuracy(y, t_org) expect(acc).toBeGreaterThan(0.95) }) + +test('semi-classifier not categorized', () => { + const model = new CoTraining( + { + fit(x, y) {}, + predict(x) { + return x.map(v => ({ category: 0, score: 0 })) + }, + threshold: 0.5, + }, + { + fit(x, y) {}, + predict(x) { + return x.map(() => ({ category: 0, score: 0 })) + }, + threshold: 0.5, + } + ) + const x = [ + [0, 0], + [1, 1], + ] + const t = [0, null] + model.init(x, t) + for (let i = 0; i < 1; i++) { + model.fit() + } + const y = model.predict(x) + expect(y).toEqual([0, null]) +}) diff --git a/tests/lib/model/confidence_weighted.test.js b/tests/lib/model/confidence_weighted.test.js index 61e445ff..b28dcc74 100644 --- a/tests/lib/model/confidence_weighted.test.js +++ b/tests/lib/model/confidence_weighted.test.js @@ -6,18 +6,34 @@ import { ConfidenceWeighted, SoftConfidenceWeighted } from '../../../lib/model/c import { accuracy } from '../../../lib/evaluate/classification.js' -test('ConfidenceWeighted', () => { - const model = new ConfidenceWeighted(0.9) - const x = Matrix.concat(Matrix.randn(50, 2, 0, 0.2), Matrix.randn(50, 2, 5, 0.2)).toArray() - const t = [] - for (let i = 0; i < x.length; i++) { - t[i] = Math.floor(i / 50) * 2 - 1 - } - model.init(x, t) - model.fit() - const y = model.predict(x) - const acc = accuracy(y, t) - expect(acc).toBeGreaterThan(0.95) +describe('ConfidenceWeighted', () => { + test('normal eta', () => { + const model = new ConfidenceWeighted(0.9) + const x = Matrix.concat(Matrix.randn(50, 2, 0, 0.2), Matrix.randn(50, 2, 5, 0.2)).toArray() + const t = [] + for (let i = 0; i < x.length; i++) { + t[i] = Math.floor(i / 50) * 2 - 1 + } + model.init(x, t) + model.fit() + const y = model.predict(x) + const acc = accuracy(y, t) + expect(acc).toBeGreaterThan(0.95) + }) + + test.each([1, 0.5, 0])('eta %p', eta => { + const model = new ConfidenceWeighted(eta) + const x = Matrix.concat(Matrix.randn(50, 2, 0, 0.2), Matrix.randn(50, 2, 5, 0.2)).toArray() + const t = [] + for (let i = 0; i < x.length; i++) { + t[i] = Math.floor(i / 50) * 2 - 1 + } + model.init(x, t) + model.fit() + const y = model.predict(x) + const acc = accuracy(y, t) + expect(acc).toBeCloseTo(0.5) + }) }) test.each([1, 2])('SoftConfidenceWeighted %d', version => { diff --git a/tests/lib/model/crf.test.js b/tests/lib/model/crf.test.js index 00402038..4ade6c59 100644 --- a/tests/lib/model/crf.test.js +++ b/tests/lib/model/crf.test.js @@ -20,3 +20,21 @@ test('fit', () => { expect(prob).toBeGreaterThan(0.4) expect(prob).toBeLessThanOrEqual(1) }) + +test('fit unknown predict label', () => { + const model = new CRF() + const x = [['a', 'b', 'c']] + const y = [[2, 0, 1]] + + for (let i = 0; i < 100; i++) { + model.fit(x, y) + } + + const tx = [['a', 'd', 'c']] + const ty = [[2, 0, 1]] + const p = model.predict(tx) + expect(p).toEqual(ty) + const prob = model.probability(tx[0], ty[0]) + expect(prob).toBeGreaterThan(0.4) + expect(prob).toBeLessThanOrEqual(1) +}) diff --git a/tests/lib/model/cubic_hermite_spline.test.js b/tests/lib/model/cubic_hermite_spline.test.js index 28d366d8..62427caa 100644 --- a/tests/lib/model/cubic_hermite_spline.test.js +++ b/tests/lib/model/cubic_hermite_spline.test.js @@ -3,23 +3,35 @@ import CubicHermiteSpline from '../../../lib/model/cubic_hermite_spline.js' import { rmse } from '../../../lib/evaluate/regression.js' -test('interpolation', () => { - const model = new CubicHermiteSpline(0, 0) - const x = Matrix.random(50, 1, -2, 2).value - const t = [] - for (let i = 0; i < x.length; i++) { - t[i] = Math.sin(x[i]) - } - model.fit(x, t) +describe('interpolation', () => { + test('default', () => { + const model = new CubicHermiteSpline(0, 0) + const x = Matrix.random(50, 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 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) + 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) + }) + + test('predict second largest value', () => { + const model = new CubicHermiteSpline(0, 0) + const x = [0, 2] + const t = [0, 1] + model.fit(x, t) + + const y = model.predict([1]) + expect(y[0]).toBeCloseTo(0.5) + }) }) diff --git a/tests/lib/model/cubic_interpolation.test.js b/tests/lib/model/cubic_interpolation.test.js index 5a37351d..a6278f24 100644 --- a/tests/lib/model/cubic_interpolation.test.js +++ b/tests/lib/model/cubic_interpolation.test.js @@ -3,23 +3,35 @@ import CubicInterpolation from '../../../lib/model/cubic_interpolation.js' import { rmse } from '../../../lib/evaluate/regression.js' -test('interpolation', () => { - const model = new CubicInterpolation() - const x = Matrix.random(50, 1, -2, 2).value - const t = [] - for (let i = 0; i < x.length; i++) { - t[i] = Math.sin(x[i]) - } - model.fit(x, t) +describe('interpolation', () => { + test('default', () => { + const model = new CubicInterpolation() + const x = Matrix.random(50, 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 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) + 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) + }) + + test('predict second largest value', () => { + const model = new CubicInterpolation() + const x = [0, 2] + const t = [0, 1] + model.fit(x, t) + + const y = model.predict([1]) + expect(y[0]).toBeCloseTo(0.5) + }) }) diff --git a/tests/lib/model/dann.test.js b/tests/lib/model/dann.test.js index 35696b68..a8844682 100644 --- a/tests/lib/model/dann.test.js +++ b/tests/lib/model/dann.test.js @@ -33,4 +33,17 @@ describe('classification', () => { const acc = accuracy(y, t) expect(acc).toBeGreaterThan(0.95) }) + + test('same number of class choice', () => { + const model = new DiscriminantAdaptiveNearestNeighbor(2) + const x = [ + [-1, -1], + [1, 1], + ] + const t = ['a', 'b'] + + model.fit(x, t) + const y = model.predict([[-1, -1]]) + expect(y).toEqual(['a']) + }) }) diff --git a/tests/lib/model/denclue.test.js b/tests/lib/model/denclue.test.js index 3a5d0398..41bae894 100644 --- a/tests/lib/model/denclue.test.js +++ b/tests/lib/model/denclue.test.js @@ -78,4 +78,20 @@ describe('clustering', () => { const ri = randIndex(y, t) expect(ri).toBeGreaterThan(0.9) }) + + test('large h', () => { + const model = new DENCLUE(1e6) + const n = 50 + const x = [ + [0, 0], + [1, 1], + ] + + model.init(x) + for (let i = 0; i < 10; i++) { + model.fit() + } + const y = model.predict() + expect(y).toEqual([-1, -1]) + }) }) diff --git a/tests/lib/model/gaussian_process.test.js b/tests/lib/model/gaussian_process.test.js index 9e0c7b09..19e45377 100644 --- a/tests/lib/model/gaussian_process.test.js +++ b/tests/lib/model/gaussian_process.test.js @@ -6,18 +6,36 @@ import GaussianProcess from '../../../lib/model/gaussian_process.js' import { rmse } from '../../../lib/evaluate/regression.js' -test('regression', () => { - const model = new GaussianProcess() - const x = Matrix.random(50, 2, -2, 2).toArray() - const t = [] - for (let i = 0; i < x.length; i++) { - t[i] = [x[i][0] + x[i][1] + (Math.random() - 0.5) / 10] - } - model.init(x, t) - for (let i = 0; i < 10; i++) { - model.fit(0.001) - } - const y = model.predict(x) - const err = rmse(y, t)[0] - expect(err).toBeLessThan(0.5) +describe('regression', () => { + test('fit default', () => { + const model = new GaussianProcess(undefined, 10) + const x = [ + [0, 0], + [1, 1], + ] + const t = [[0], [1]] + model.init(x, t) + for (let i = 0; i < 10; i++) { + model.fit() + } + const y = model.predict(x) + const err = rmse(y, t)[0] + expect(err).toBeLessThan(0.5) + }) + + test('fit with param', () => { + const model = new GaussianProcess() + const x = Matrix.random(50, 2, -2, 2).toArray() + const t = [] + for (let i = 0; i < x.length; i++) { + t[i] = [x[i][0] + x[i][1] + (Math.random() - 0.5) / 10] + } + model.init(x, t) + for (let i = 0; i < 10; i++) { + model.fit(0.001) + } + const y = model.predict(x) + const err = rmse(y, t)[0] + expect(err).toBeLessThan(0.5) + }) }) diff --git a/tests/lib/model/gmm.test.js b/tests/lib/model/gmm.test.js index b4b27f4f..bc190c28 100644 --- a/tests/lib/model/gmm.test.js +++ b/tests/lib/model/gmm.test.js @@ -34,6 +34,22 @@ describe('clustering', () => { expect(ri).toBeGreaterThan(0.9) }) + test('clear', () => { + const model = new GMM() + const x = [ + [0, 0], + [1, 1], + ] + model.add() + model.add() + for (let i = 0; i < 100; i++) { + model.fit(x) + } + expect(model._k).toBe(2) + model.clear() + expect(model._k).toBe(0) + }) + test('probability', () => { const model = new GMM() const n = 50 @@ -55,22 +71,65 @@ describe('clustering', () => { }) }) -test('regression', () => { - const model = new GMR() - const x = Matrix.randn(50, 2, 0, 5).toArray() - const t = [] - for (let i = 0; i < x.length; i++) { - t[i] = [x[i][0] + x[i][1] + (Math.random() - 0.5) / 10] - } - model.add() - model.add() - model.add() - for (let i = 0; i < 20; i++) { +describe('regression', () => { + test('predict', () => { + const model = new GMR() + const x = Matrix.randn(50, 2, 0, 5).toArray() + const t = [] + for (let i = 0; i < x.length; i++) { + t[i] = [x[i][0] + x[i][1] + (Math.random() - 0.5) / 10] + } + model.add() + model.add() + model.add() + for (let i = 0; i < 20; i++) { + model.fit(x, t) + } + const y = model.predict(x) + const err = rmse(y, t)[0] + expect(err).toBeLessThan(0.5) + }) + + test('clear', () => { + const model = new GMR() + const x = [ + [0, 0], + [1, 1], + ] + const t = [[0], [1]] + model.add() + model.add() model.fit(x, t) - } - const y = model.predict(x) - const err = rmse(y, t)[0] - expect(err).toBeLessThan(0.5) + expect(model._k).toBe(2) + model.clear() + expect(model._k).toBe(0) + }) + + test('probability', () => { + const model = new GMR() + const x = [ + [0, 0], + [1, 1], + ] + const t = [[0], [1]] + + model.add() + model.add() + for (let i = 0; i < 100; i++) { + model.fit(x, t) + } + + const p = model.probability( + [ + [0, 0], + [-1, -1], + ], + [[0], [-1]] + ) + for (let c = 0; c < 2; c++) { + expect(p[0][c]).toBeGreaterThan(p[1][c]) + } + }) }) test('semi-classifier', () => { diff --git a/tests/lib/model/hmm.test.js b/tests/lib/model/hmm.test.js index 937bafdd..4d2203b1 100644 --- a/tests/lib/model/hmm.test.js +++ b/tests/lib/model/hmm.test.js @@ -97,4 +97,17 @@ describe('continuous hmm', () => { expect(mean).toBeCloseTo(0, 1) expect(vari).toBeCloseTo(1, 0) }) + + test('generate default', () => { + const model = new ContinuousHMM(5) + const x = Tensor.randn([10, 7, 2]).toArray() + model.fit(x, true) + + const gen = model.generate() + expect(gen).toHaveLength(1) + + for (let i = 0; i < gen.length; i++) { + expect(gen[i]).toHaveLength(5) + } + }) }) diff --git a/tests/lib/model/hopfield.test.js b/tests/lib/model/hopfield.test.js index 87765366..79d775fd 100644 --- a/tests/lib/model/hopfield.test.js +++ b/tests/lib/model/hopfield.test.js @@ -16,3 +16,13 @@ test('reconstruct', () => { const y2 = model.predict([-1, 1, -1, 1, 1, 1]) expect(y2).toEqual(x2) }) + +test('reconstruct one', () => { + const model = new Hopfield() + const x = [1] + model.fit([x]) + const energy = model.energy(x) + expect(energy).toBe(0) + const y = model.predict(x) + expect(y).toEqual([1]) +}) diff --git a/tests/lib/model/ica.test.js b/tests/lib/model/ica.test.js index 19383d08..82f7bf6d 100644 --- a/tests/lib/model/ica.test.js +++ b/tests/lib/model/ica.test.js @@ -34,4 +34,16 @@ describe('dimensionality reduction', () => { const q = coRankingMatrix(x, y, 30, 20) expect(q).toBeGreaterThan(0.9) }) + + test('fit twice', () => { + const x = [ + [0, 0], + [1, 1], + ] + const model = new ICA() + model.fit(x) + model.fit(x) + const y = model.predict(x) + expect(y[0]).toHaveLength(2) + }) }) diff --git a/tests/lib/model/iknn.test.js b/tests/lib/model/iknn.test.js index 61c520b8..33b12fdb 100644 --- a/tests/lib/model/iknn.test.js +++ b/tests/lib/model/iknn.test.js @@ -17,3 +17,19 @@ test('predict', () => { const acc = accuracy(y, t) expect(acc).toBeGreaterThan(0.9) }) + +test('same number of class choice', () => { + const model = new IKNN(2, 2) + const x = [ + [-1, -1], + [1, 1], + ] + const t = ['a', 'b'] + + model.fit(x, t) + const y = model.predict([ + [-1, -1], + [1, 1], + ]) + expect(y).toEqual(['a', 'b']) +}) diff --git a/tests/lib/model/incremental_pca.test.js b/tests/lib/model/incremental_pca.test.js index bc672a67..0b40bcd4 100644 --- a/tests/lib/model/incremental_pca.test.js +++ b/tests/lib/model/incremental_pca.test.js @@ -25,4 +25,17 @@ describe('dimensionality reduction', () => { const q = coRankingMatrix(x, y, 30, 20) expect(q).toBeGreaterThan(0.9) }) + + test('fit twice', () => { + const x = [ + [0, 0], + [1, 1], + ] + const model = new IncrementalPCA() + model.fit(x) + model.fit(x) + + const y = model.predict(x) + expect(y[0]).toHaveLength(2) + }) }) diff --git a/tests/lib/model/isotonic.test.js b/tests/lib/model/isotonic.test.js index 5cc787a4..e6d6aa8f 100644 --- a/tests/lib/model/isotonic.test.js +++ b/tests/lib/model/isotonic.test.js @@ -15,3 +15,13 @@ test('fit', () => { const err = rmse(y, t) expect(err).toBeLessThan(0.5) }) + +test('fit c not match', () => { + const model = new IsotonicRegression() + const x = [0.0, 1.2, 1.5, 1.1] + const t = [0.0, 1.4, 1.3, 1.6] + model.fit(x, t) + const y = model.predict(x) + const err = rmse(y, t) + expect(err).toBeLessThan(1.0) +}) diff --git a/tests/lib/model/kalman_filter.test.js b/tests/lib/model/kalman_filter.test.js index e9651652..649b5eab 100644 --- a/tests/lib/model/kalman_filter.test.js +++ b/tests/lib/model/kalman_filter.test.js @@ -2,16 +2,33 @@ import KalmanFilter from '../../../lib/model/kalman_filter.js' import { rmse } from '../../../lib/evaluate/regression.js' -test('smoothing', () => { - const x = [] - const t = [] - for (let i = 0; i < 100; i++) { - x[i] = [Math.sin(i / 50) + (Math.random() - 0.5) / 2] - t[i] = [Math.sin(i / 50)] - } - const model = new KalmanFilter() - const y = model.fit(x) - expect(y).toHaveLength(t.length) - const err = rmse(y, t)[0] - expect(err).toBeLessThan(rmse(x, t)[0]) +describe('smoothing', () => { + test('small dim', () => { + const x = [] + const t = [] + for (let i = 0; i < 100; i++) { + x[i] = [Math.sin(i / 50) + (Math.random() - 0.5) / 2] + t[i] = [Math.sin(i / 50)] + } + const model = new KalmanFilter() + const y = model.fit(x) + expect(y).toHaveLength(t.length) + const err = rmse(y, t)[0] + expect(err).toBeLessThan(rmse(x, t)[0]) + }) + + test('large dim', () => { + const x = [] + const t = [] + for (let i = 0; i < 100; i++) { + const v = Math.sin(i / 50) + (Math.random() - 0.5) / 2 + x[i] = Array.from({ length: 12 }, () => v) + t[i] = [Math.sin(i / 50)] + } + const model = new KalmanFilter() + const y = model.fit(x) + expect(y).toHaveLength(t.length) + const err = rmse(y, t)[0] + expect(err).toBeLessThan(Infinity) + }) }) diff --git a/tests/lib/model/knearestneighbor.test.js b/tests/lib/model/knearestneighbor.test.js index e81d9330..ed4f41ad 100644 --- a/tests/lib/model/knearestneighbor.test.js +++ b/tests/lib/model/knearestneighbor.test.js @@ -33,6 +33,22 @@ describe.each([ const acc = accuracy(y, t) expect(acc).toBeGreaterThan(0.95) }) + + test('same number of class choice', () => { + const model = new KNN(2) + const x = [ + [-1, -1], + [1, 1], + ] + const t = ['a', 'b'] + + model.fit(x, t) + const y = model.predict([ + [-1, -1], + [1, 1], + ]) + expect(y).toEqual(['a', 'b']) + }) }) describe.each([ diff --git a/tests/lib/model/ksvd.test.js b/tests/lib/model/ksvd.test.js index 16c03c39..2d260420 100644 --- a/tests/lib/model/ksvd.test.js +++ b/tests/lib/model/ksvd.test.js @@ -17,3 +17,12 @@ test('dimensionality reduction', () => { const q = coRankingMatrix(x, y, 30, 20) expect(q).toBeGreaterThan(0.9) }) + +test('dimensionality reduction small norm', () => { + const x = [[0, 0, 0, 0, 0]] + const model = new KSVD(x, 2) + + model.fit() + const y = model.predict() + expect(y).toEqual([[0, 0]]) +}) diff --git a/tests/lib/model/label_propagation.test.js b/tests/lib/model/label_propagation.test.js index 9025b8c7..80be4ce8 100644 --- a/tests/lib/model/label_propagation.test.js +++ b/tests/lib/model/label_propagation.test.js @@ -22,3 +22,23 @@ test.each([undefined, 'rbf', { name: 'rbf', sigma: 0.2 }, { name: 'knn', k: 10 } const acc = accuracy(y, t_org) expect(acc).toBeGreaterThan(0.95) }) + +test('semi-classifier k=0', () => { + const model = new LabelPropagation({ name: 'rbf', sigma: 0.1, k: 0 }) + const x = Matrix.concat(Matrix.randn(50, 2, 0, 0.2), Matrix.randn(50, 2, 5, 0.2)).toArray() + const t = [] + const t_org = [] + for (let i = 0; i < x.length; i++) { + t_org[i] = t[i] = String.fromCharCode('a'.charCodeAt(0) + Math.floor(i / 50)) + if (Math.random() < 0.5) { + t[i] = null + } + } + model.init(x, t) + for (let i = 0; i < 20; i++) { + model.fit() + } + const y = model.predict(x) + const acc = accuracy(y, t_org) + expect(acc).toBeGreaterThan(0.6) +}) diff --git a/tests/lib/model/label_spreading.test.js b/tests/lib/model/label_spreading.test.js index e21c51b2..1339a254 100644 --- a/tests/lib/model/label_spreading.test.js +++ b/tests/lib/model/label_spreading.test.js @@ -26,3 +26,23 @@ test.each([ const acc = accuracy(y, t_org) expect(acc).toBeGreaterThan(0.95) }) + +test('semi-classifier k=0', () => { + const model = new LabelSpreading(0.5, { name: 'rbf', sigma: 0.1, k: 0 }) + const x = Matrix.concat(Matrix.randn(50, 2, 0, 0.2), Matrix.randn(50, 2, 5, 0.2)).toArray() + const t = [] + const t_org = [] + for (let i = 0; i < x.length; i++) { + t_org[i] = t[i] = String.fromCharCode('a'.charCodeAt(0) + Math.floor(i / 50)) + if (Math.random() < 0.5) { + t[i] = null + } + } + model.init(x, t) + for (let i = 0; i < 20; i++) { + model.fit() + } + const y = model.predict(x) + const acc = accuracy(y, t_org) + expect(acc).toBeGreaterThanOrEqual(0.5) +}) diff --git a/tests/lib/model/ladder_network.test.js b/tests/lib/model/ladder_network.test.js index 74f6ff90..95332592 100644 --- a/tests/lib/model/ladder_network.test.js +++ b/tests/lib/model/ladder_network.test.js @@ -26,3 +26,17 @@ test('semi-classifier', () => { const acc = accuracy(y, t_org) expect(acc).toBeGreaterThan(0.95) }) + +test('semi-classifier learn only', () => { + const model = new LadderNetwork([5], [0.001, 0.0001, 0.0001], 'tanh', 'adam') + const x = [ + [0, 0], + [1, 1], + ] + const t = ['a', 'a'] + model.fit([[0, 0]], ['a'], 1, 0.001) + model.fit([[1, 1]], [null], 1, 0.001) + const y = model.predict(x) + const acc = accuracy(y, t) + expect(acc).toBeGreaterThan(0.95) +}) diff --git a/tests/lib/model/laplacian_eigenmaps.test.js b/tests/lib/model/laplacian_eigenmaps.test.js index 0e75ae10..88922b80 100644 --- a/tests/lib/model/laplacian_eigenmaps.test.js +++ b/tests/lib/model/laplacian_eigenmaps.test.js @@ -17,3 +17,13 @@ describe.each([undefined, 'knn', { name: 'rbf' }])('dimensionality reduction aff expect(q).toBeGreaterThan(0.9) }) }) + +test('dimensionality k=0', () => { + const x = Matrix.concat(Matrix.randn(30, 5, 0, 0.2), Matrix.randn(30, 5, 5, 0.2)).toArray() + const model = new LaplacianEigenmaps(2, { name: 'rbf', k: 0 }) + + const y = model.predict(x) + expect(y[0]).toHaveLength(2) + const q = coRankingMatrix(x, y, 20, 20) + expect(q).toBeGreaterThan(0.7) +}) diff --git a/tests/lib/model/lmclus.test.js b/tests/lib/model/lmclus.test.js index 626b6251..eb532192 100644 --- a/tests/lib/model/lmclus.test.js +++ b/tests/lib/model/lmclus.test.js @@ -15,6 +15,7 @@ test('clustering', () => { ).toArray() model.fit(x) + expect(model.size).toBeGreaterThanOrEqual(3) const y = model.predict() expect(y).toHaveLength(x.length) diff --git a/tests/lib/model/markov_switching.test.js b/tests/lib/model/markov_switching.test.js index aff40d76..f68355db 100644 --- a/tests/lib/model/markov_switching.test.js +++ b/tests/lib/model/markov_switching.test.js @@ -33,3 +33,14 @@ test('anomaly detection', () => { expect(Math.abs(prob[0][0] - prob[0][1])).toBeCloseTo(1) expect(prob[0][0] - prob[0][1]).toBeCloseTo(prob[1][1] - prob[1][0]) }) + +test('anomaly detection fit twice', () => { + const model = new MarkovSwitching(2) + const n = 50 + const x = Matrix.concat(Matrix.random(n, 2, 0, 1), Matrix.random(n, 2, 2, 3)).toArray() + + model.fit(x, 1, 1) + model.fit(x, 1, 1) + const p = model.predict(x) + expect(p).toHaveLength(99) +}) diff --git a/tests/lib/model/mars.test.js b/tests/lib/model/mars.test.js index 0718c61a..9c03ef1a 100644 --- a/tests/lib/model/mars.test.js +++ b/tests/lib/model/mars.test.js @@ -15,3 +15,33 @@ test('fit', () => { const err = rmse(y, t)[0] expect(err).toBeLessThan(0.5) }) + +test('fit update best lof', () => { + const model = new MARS(20) + const x = [ + [0.4946112861933446, -0.24979407544789328], + [0.6710977380517686, 2.760557507387143], + [-0.5451316855831966, -1.7861984864750804], + [1.5413600325044114, 0.6113068721545195], + [-0.15915692646845286, 0.36163408767347377], + [-4.456221847339759, 2.6448274560926066], + [0.9859756767948494, -0.7623872449215827], + [1.6964768061759719, 4.561617731454047], + [-3.0039970134614746, 3.7582323314173856], + ] + const t = [ + [5.0135998349450785], + [8.344300706946722], + [2.8613517704846276], + [6.965641204443869], + [5.4431303914749085], + [3.072585145244251], + [5.404783275862362], + [11.42125315864682], + [5.875750792935508], + ] + model.fit(x, t) + const y = model.predict(x) + const err = rmse(y, t)[0] + expect(err).toBeLessThan(0.5) +}) diff --git a/tests/lib/model/mlle.test.js b/tests/lib/model/mlle.test.js index 34cbcbb3..79bdab14 100644 --- a/tests/lib/model/mlle.test.js +++ b/tests/lib/model/mlle.test.js @@ -22,4 +22,22 @@ describe('dimensionality reduction', () => { const q = coRankingMatrix(x, y, 20, 30) expect(q).toBeGreaterThan(0.9) }) + + test('odd size and less than eta', () => { + const x = [ + [-0.48, -0.18, -0.14], + [0.44, -0.35, 0.08], + [-0.15, 0.76, 0.11], + [-0.52, -0.33, 0.12], + [5.51, 5.27, 5.07], + [4.63, 4.63, 5.03], + [4.55, 4.58, 4.66], + [4.7, 4.5, 5.5], + [5.53, 4.53, 4.77], + ] + const y = new MLLE(8).predict(x) + expect(y[0]).toHaveLength(3) + const q = coRankingMatrix(x, y, 4, 5) + expect(q).toBeGreaterThan(0.95) + }) }) diff --git a/tests/lib/model/mod.test.js b/tests/lib/model/mod.test.js index 2b36c251..95c8be9a 100644 --- a/tests/lib/model/mod.test.js +++ b/tests/lib/model/mod.test.js @@ -17,3 +17,12 @@ test('dimensionality reduction', () => { const q = coRankingMatrix(x, y, 30, 20) expect(q).toBeGreaterThan(0.9) }) + +test('dimensionality reduction small norm', () => { + const x = [[0, 0, 0, 0, 0]] + const model = new MOD(x, 2) + + model.fit() + const y = model.predict() + expect(y).toEqual([[0, 0]]) +}) diff --git a/tests/lib/model/optics.test.js b/tests/lib/model/optics.test.js index 33c1d798..adec0de6 100644 --- a/tests/lib/model/optics.test.js +++ b/tests/lib/model/optics.test.js @@ -46,4 +46,14 @@ describe('clustering', () => { const ri = randIndex(y, t) expect(ri).toBeGreaterThan(0.9) }) + + test('large minpts', () => { + const model = new OPTICS(0.4, 0, 100) + const n = 100 + const x = Matrix.concat(Matrix.randn(n, 2, 0, 0.1), Matrix.randn(n, 2, 5, 0.1)).toArray() + + model.fit(x) + const y = model.predict() + expect(y).toHaveLength(x.length) + }) }) diff --git a/tests/lib/model/pegasos.test.js b/tests/lib/model/pegasos.test.js index e6e478de..f1363443 100644 --- a/tests/lib/model/pegasos.test.js +++ b/tests/lib/model/pegasos.test.js @@ -18,3 +18,20 @@ test('fit', () => { const acc = accuracy(y, t) expect(acc).toBeGreaterThan(0.9) }) + +test('fit do projection', () => { + const model = new Pegasos(0.05) + model._do_projection = true + const x = Matrix.concat(Matrix.randn(50, 2, 0, 0.2), Matrix.randn(50, 2, 5, 0.2)).toArray() + const t = [] + for (let i = 0; i < x.length; i++) { + t[i] = Math.floor(i / 50) * 2 - 1 + } + model.init(x, t) + for (let i = 0; i < 100; i++) { + model.fit() + } + const y = model.predict(x) + const acc = accuracy(y, t) + expect(acc).toBeGreaterThan(0.9) +}) diff --git a/tests/lib/model/pls.test.js b/tests/lib/model/pls.test.js index f6408f8e..3febd6bf 100644 --- a/tests/lib/model/pls.test.js +++ b/tests/lib/model/pls.test.js @@ -12,7 +12,7 @@ describe('regression', () => { t[i] = [x[i][0] + x[i][1] + (Math.random() - 0.5) / 100] } model.init(x, t) - model.fit(x, t) + model.fit() const y = model.predict(x) const err = rmse(y, t)[0] @@ -27,6 +27,6 @@ describe('regression', () => { t[i] = [0, 0] } model.init(x, t) - expect(() => model.fit(x, t)).toThrow() + expect(() => model.fit()).toThrow() }) }) diff --git a/tests/lib/model/rbm.test.js b/tests/lib/model/rbm.test.js index a9552632..2c8aabdc 100644 --- a/tests/lib/model/rbm.test.js +++ b/tests/lib/model/rbm.test.js @@ -4,24 +4,47 @@ jest.retryTimes(5) import Matrix from '../../../lib/util/matrix.js' import { RBM, GBRBM } from '../../../lib/model/rbm.js' -test('reconstruct RBM', () => { - const model = new RBM(10) - const x = [ - [1, 1, 1, 1, 0, 0, 0], - [0, 0, 0, 0, 1, 1, 1], - ] - model.fit(x) - const oldenergy = model.energy(x[0], model._h([x[0]], false)[0]) - for (let i = 0; i < 10000; i++) { +describe('reconstruct RBM', () => { + test('default', () => { + const model = new RBM(10) + const x = [ + [1, 1, 1, 1, 0, 0, 0], + [0, 0, 0, 0, 1, 1, 1], + ] model.fit(x) - } - const newenergy = model.energy(x[0], model._h([x[0]], false)[0]) - expect(newenergy).toBeLessThanOrEqual(oldenergy) - const y = model.predict([ - [1, 0, 1, 1, 0, 0, 0], - [0, 1, 0, 0, 1, 1, 1], - ]) - expect(y).toEqual(x) + const oldenergy = model.energy(x[0], model._h([x[0]], false)[0]) + for (let i = 0; i < 10000; i++) { + model.fit(x) + } + const newenergy = model.energy(x[0], model._h([x[0]], false)[0]) + expect(newenergy).toBeLessThanOrEqual(oldenergy) + const y = model.predict([ + [1, 0, 1, 1, 0, 0, 0], + [0, 1, 0, 0, 1, 1, 1], + ]) + expect(y).toEqual(x) + }) + + test('k=2', () => { + const model = new RBM(10) + model._k = 2 + const x = [ + [1, 1, 1, 1, 0, 0, 0], + [0, 0, 0, 0, 1, 1, 1], + ] + model.fit(x) + const oldenergy = model.energy(x[0], model._h([x[0]], false)[0]) + for (let i = 0; i < 10000; i++) { + model.fit(x) + } + const newenergy = model.energy(x[0], model._h([x[0]], false)[0]) + expect(newenergy).toBeLessThanOrEqual(oldenergy) + const y = model.predict([ + [1, 0, 1, 1, 0, 0, 0], + [0, 1, 0, 0, 1, 1, 1], + ]) + expect(y).toEqual(x) + }) }) test('reconstruct GBRBM', () => { diff --git a/tests/lib/model/sdar.test.js b/tests/lib/model/sdar.test.js index d2e4539d..54abad57 100644 --- a/tests/lib/model/sdar.test.js +++ b/tests/lib/model/sdar.test.js @@ -1,23 +1,38 @@ import SDAR from '../../../lib/model/sdar.js' -test('linear', () => { - const model = new SDAR(10, 0.1) - const x = [] - for (let i = 0; i < 1000; i++) { - x[i] = i / 10 - } +describe('probability', () => { + test('linear', () => { + const model = new SDAR(10, 0.1) + const x = [] + for (let i = 0; i < 100; i++) { + x[i] = i / 10 + } - const future = model.predict(x, 20) - expect(future).toHaveLength(20) + const prob = model.probability(x) + expect(prob).toHaveLength(100) + }) }) -test('sin', () => { - const model = new SDAR(50) - const x = [] - for (let i = 0; i < 1000; i++) { - x[i] = Math.sin(i / 10) - } +describe('predict', () => { + test('linear', () => { + const model = new SDAR(10, 0.1) + const x = [] + for (let i = 0; i < 1000; i++) { + x[i] = i / 10 + } - const future = model.predict(x, 50) - expect(future).toHaveLength(50) + const future = model.predict(x, 20) + expect(future).toHaveLength(20) + }) + + test('sin', () => { + const model = new SDAR(50) + const x = [] + for (let i = 0; i < 1000; i++) { + x[i] = Math.sin(i / 10) + } + + const future = model.predict(x, 50) + expect(future).toHaveLength(50) + }) }) diff --git a/tests/lib/model/self_training.test.js b/tests/lib/model/self_training.test.js index 5aacb571..48ed5cf4 100644 --- a/tests/lib/model/self_training.test.js +++ b/tests/lib/model/self_training.test.js @@ -46,3 +46,27 @@ test('semi-classifier', () => { const acc = accuracy(y, t_org) expect(acc).toBeGreaterThan(0.95) }) + +test('semi-classifier', () => { + const dt = new DecisionTreeClassifier('CART') + const model = new SelfTraining( + { + fit(x, y) {}, + predict(x) { + return x.map(() => ({ category: 0, score: 0 })) + }, + }, + 0.5 + ) + const x = [ + [0, 0], + [1, 1], + ] + const t = [0, null] + model.init(x, t) + for (let i = 0; i < 1; i++) { + model.fit() + } + const y = model.predict(x) + expect(y).toEqual([0, null]) +}) diff --git a/tests/lib/model/semi_supervised_naive_bayes.test.js b/tests/lib/model/semi_supervised_naive_bayes.test.js index 2185b8ca..b352d87c 100644 --- a/tests/lib/model/semi_supervised_naive_bayes.test.js +++ b/tests/lib/model/semi_supervised_naive_bayes.test.js @@ -36,3 +36,15 @@ test('semi-classifier', () => { const acc = accuracy(y, t_org) expect(acc).toBeGreaterThan(0.95) }) + +test('semi-classifier unknown data', () => { + const model = new SemiSupervisedNaiveBayes() + const x = [['May', 'I', 'have', 'a', 'large', 'container', 'of', 'coffee']] + const t = ['a'] + + model.init(x, t) + model.fit() + + const y = model.predict([['Dummy']]) + expect(y).toEqual([null]) +}) diff --git a/tests/lib/model/smirnov_grubbs.test.js b/tests/lib/model/smirnov_grubbs.test.js index 2d8a9f55..1f031ed6 100644 --- a/tests/lib/model/smirnov_grubbs.test.js +++ b/tests/lib/model/smirnov_grubbs.test.js @@ -19,4 +19,52 @@ describe('anomaly detection', () => { const y = model.predict(x) expect(y).toEqual([false, false]) }) + + test('no outlier', () => { + const model = new SmirnovGrubbs(1) + const x = [] + for (let i = 0; i < 100; i++) { + for (let j = 0; j < 100; j++) { + x.push([i / 100, j / 100]) + } + } + const y = model.predict(x) + for (let i = 0; i < y.length; i++) { + expect(y[i]).toBe(false) + } + }) + + test('p is 1', () => { + const model = new SmirnovGrubbs(3) + const x = [ + [0, 0], + [1, 1], + [2, 2], + ] + const y = model.predict(x) + expect(y).toEqual([false, false, false]) + }) + + test('p is over 0.5', () => { + const model = new SmirnovGrubbs(2) + const x = [ + [0, 0], + [1, 1], + [2, 2], + ] + const y = model.predict(x) + expect(y).toEqual([true, false, false]) + }) + + test('n is 2', () => { + const model = new SmirnovGrubbs(2) + const x = [ + [0, 0], + [1, 1], + [2, 2], + [3, 3], + ] + const y = model.predict(x) + expect(y).toEqual([true, false, false, false]) + }) }) diff --git a/tests/lib/model/snakes.test.js b/tests/lib/model/snakes.test.js index 688a8d3d..7d4e1d4f 100644 --- a/tests/lib/model/snakes.test.js +++ b/tests/lib/model/snakes.test.js @@ -1,38 +1,72 @@ import Tensor from '../../../lib/util/tensor.js' import Snakes from '../../../lib/model/snakes.js' -test('predict', () => { - const model = new Snakes(1, 1, 1, 12) - const n = 100 - const x = Tensor.zeros([n, n, 1]).toArray() - for (let i = 0; i < n; i++) { - for (let j = 0; j < n; j++) { - if ((i - n / 2) ** 2 + (j - n / 2) ** 2 < (n / 4) ** 2) { - x[i][j][0] = 255 +describe('predict', () => { + test('default', () => { + const model = new Snakes(1, 1, 1) + const n = 10 + const x = Tensor.zeros([n, n, 1]).toArray() + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if ((i - n / 2) ** 2 + (j - n / 2) ** 2 < (n / 4) ** 2) { + x[i][j][0] = 255 + } } } - } - model.init(x) - for (let i = 0; i < 100; i++) { + model.init(x) model.fit() - } - const y = model.predict(x) - const b = [0, 0] - for (let i = 0; i < n; i++) { - for (let j = 0; j < n; j++) { - const r2 = (i - n / 2) ** 2 + (j - n / 2) ** 2 - if ((n / 4 - 2) ** 2 < r2 && r2 < (n / 4 + 2) ** 2) { - if (y[i][j]) { - b[0]++ - } else { - b[1]++ + const y = model.predict(x) + const b = [0, 0] + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + const r2 = (i - n / 2) ** 2 + (j - n / 2) ** 2 + if ((n / 4 - 2) ** 2 < r2 && r2 < (n / 4 + 2) ** 2) { + if (y[i][j]) { + b[0]++ + } else { + b[1]++ + } + } + } + } + expect(b[0] / (b[0] + b[1])).toBeGreaterThan(0.1) + }) + + test('with params', () => { + const model = new Snakes(1, 1, 1, 12) + const n = 100 + const x = Tensor.zeros([n, n, 1]).toArray() + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if ((i - n / 2) ** 2 + (j - n / 2) ** 2 < (n / 4) ** 2) { + x[i][j][0] = 255 + } + } + } + + model.init(x) + for (let i = 0; i < 100; i++) { + model.fit() + } + + const y = model.predict(x) + const b = [0, 0] + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + const r2 = (i - n / 2) ** 2 + (j - n / 2) ** 2 + if ((n / 4 - 2) ** 2 < r2 && r2 < (n / 4 + 2) ** 2) { + if (y[i][j]) { + b[0]++ + } else { + b[1]++ + } + continue } - continue + expect(y[i][j]).toBe(false) } - expect(y[i][j]).toBe(false) } - } - expect(b[0] / (b[0] + b[1])).toBeGreaterThan(0.2) + expect(b[0] / (b[0] + b[1])).toBeGreaterThan(0.2) + }) }) diff --git a/tests/lib/model/svm.test.js b/tests/lib/model/svm.test.js index 7ec3bdc6..2cacdbd0 100644 --- a/tests/lib/model/svm.test.js +++ b/tests/lib/model/svm.test.js @@ -38,4 +38,20 @@ describe('classification', () => { const acc = accuracy(y.map(Math.sign), t.map(Math.sign)) expect(acc).toBeGreaterThan(0.9) }) + + test('uniform kernel', () => { + const model = new SVM((a, b) => (a.reduce((s, v, i) => s + (v - b[i]) ** 2, 0) < 1 ? 1 : 0)) + const x = Matrix.concat(Matrix.randn(50, 2, 0, 0.2), Matrix.randn(50, 2, 5, 0.2)).toArray() + const t = [] + for (let i = 0; i < x.length; i++) { + t[i] = Math.floor(i / 50) * 2 - 1 + } + model.init(x, t) + for (let i = 0; i < 100; i++) { + model.fit() + } + const y = model.predict(x) + const acc = accuracy(y.map(Math.sign), t.map(Math.sign)) + expect(acc).toBeGreaterThan(0.9) + }) }) diff --git a/tests/lib/model/thompson.test.js b/tests/lib/model/thompson.test.js index db4e1bd2..4a7acdcf 100644 --- a/tests/lib/model/thompson.test.js +++ b/tests/lib/model/thompson.test.js @@ -19,4 +19,52 @@ describe('anomaly detection', () => { const y = model.predict(x) expect(y).toEqual([false, false]) }) + + test('no outlier', () => { + const model = new Thompson(1) + const x = [] + for (let i = 0; i < 100; i++) { + for (let j = 0; j < 100; j++) { + x.push([i / 100, j / 100]) + } + } + const y = model.predict(x) + for (let i = 0; i < y.length; i++) { + expect(y[i]).toBe(false) + } + }) + + test('p is 1', () => { + const model = new Thompson(3) + const x = [ + [0, 0], + [1, 1], + [2, 2], + ] + const y = model.predict(x) + expect(y).toEqual([false, false, false]) + }) + + test('p is over 0.5', () => { + const model = new Thompson(2) + const x = [ + [0, 0], + [1, 1], + [2, 2], + ] + const y = model.predict(x) + expect(y).toEqual([true, false, false]) + }) + + test('n is 2', () => { + const model = new Thompson(2) + const x = [ + [0, 0], + [1, 1], + [2, 2], + [3, 3], + ] + const y = model.predict(x) + expect(y).toEqual([true, false, false, false]) + }) }) diff --git a/tests/lib/model/tietjen_moore.test.js b/tests/lib/model/tietjen_moore.test.js index 4099274d..47ab8534 100644 --- a/tests/lib/model/tietjen_moore.test.js +++ b/tests/lib/model/tietjen_moore.test.js @@ -19,3 +19,17 @@ test.each([1, 2, 3])('anomaly detection %d', k => { expect(c).toBe(k - 1) expect(y[y.length - 1]).toBe(true) }) + +test('no outlier', () => { + const model = new TietjenMoore(1, 0.1) + const x = [] + for (let i = 0; i < 100; i++) { + for (let j = 0; j < 100; j++) { + x.push([i / 100, j / 100]) + } + } + const y = model.predict(x) + for (let i = 0; i < y.length; i++) { + expect(y[i]).toBe(false) + } +}) diff --git a/tests/lib/model/tsne.test.js b/tests/lib/model/tsne.test.js index 99663cc4..0ac12b35 100644 --- a/tests/lib/model/tsne.test.js +++ b/tests/lib/model/tsne.test.js @@ -19,6 +19,18 @@ describe('SNE dimension reduction', () => { const q = coRankingMatrix(x, y, 10, 10) expect(q).toBeGreaterThan(0.9) }) + + test('infinite sigma', () => { + const x = [ + [0, 0], + [1, 1], + ] + const model = new SNE(x, 1) + + model.fit() + const y = model.predict() + expect(y).toHaveLength(2) + }) }) describe('tSNE dimension reduction', () => { @@ -33,4 +45,16 @@ describe('tSNE dimension reduction', () => { const q = coRankingMatrix(x, y, 10, 10) expect(q).toBeGreaterThan(0.9) }) + + test('infinite sigma', () => { + const x = [ + [0, 0], + [1, 1], + ] + const model = new tSNE(x, 1) + + model.fit() + const y = model.predict() + expect(y).toHaveLength(2) + }) }) diff --git a/tests/lib/model/word_to_vec.test.js b/tests/lib/model/word_to_vec.test.js index e7152b0a..1cdf6523 100644 --- a/tests/lib/model/word_to_vec.test.js +++ b/tests/lib/model/word_to_vec.test.js @@ -35,6 +35,19 @@ describe.each(['CBOW', 'skip-gram'])('embedding %s', method => { expect(y[i]).toHaveLength(2) } }) + + test('small number of words', () => { + const x = ['May', 'I', 'have', 'a', 'large', 'container', 'of', 'coffee'] + const model = new Word2Vec(method, 1, 3, 2, 'adam') + + model.fit(x, 1, 0.1, 10) + + const y = model.reduce(x) + expect(y).toHaveLength(x.length) + for (let i = 0; i < y.length; i++) { + expect(y[i]).toHaveLength(2) + } + }) }) test('predict unknown', () => {