Skip to content

Commit bbcb451

Browse files
authored
Remove init_args from EnsembleBinaryModel (#43)
1 parent 55fcfd1 commit bbcb451

35 files changed

+1405
-29
lines changed

js/view/adaline.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ var dispADALINE = function (elm, platform) {
99
platform.fit((tx, ty) => {
1010
ty = ty.map(v => v[0])
1111
if (!model) {
12-
model = new EnsembleBinaryModel(ADALINE, method, null, [rate])
12+
model = new EnsembleBinaryModel(function () {
13+
return new ADALINE(rate)
14+
}, method)
1315
model.init(tx, ty)
1416
}
1517
model.fit()

js/view/alma.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ var dispALMA = function (elm, platform) {
1010
const alpha = +elm.select('[name=alpha]').property('value')
1111
const b = +elm.select('[name=b]').property('value')
1212
const c = +elm.select('[name=c]').property('value')
13-
const model = new EnsembleBinaryModel(ALMA, method, null, [p, alpha, b, c])
13+
const model = new EnsembleBinaryModel(function () {
14+
return new ALMA(p, alpha, b, c)
15+
}, method)
1416
model.init(tx, ty)
1517
model.fit()
1618

js/view/arow.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ var dispAROW = function (elm, platform) {
77
const r = +elm.select('[name=r]').property('value')
88
platform.fit((tx, ty) => {
99
ty = ty.map(v => v[0])
10-
const model = new EnsembleBinaryModel(AROW, method, null, [r])
10+
const model = new EnsembleBinaryModel(function () {
11+
return new AROW(r)
12+
}, method)
1113
model.init(tx, ty)
1214
model.fit()
1315

js/view/confidence_weighted.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ var dispConfidenceWeighted = function (elm, platform) {
1111
ty = ty.map(v => v[0])
1212
const mdl = type === 'cw' ? ConfidenceWeighted : SoftConfidenceWeighted
1313
const prm = type === 'cw' ? [eta] : [eta, cost, type === 'scw-1' ? 1 : 2]
14-
const model = new EnsembleBinaryModel(mdl, method, null, prm)
14+
const model = new EnsembleBinaryModel(function () {
15+
return new mdl(...prm)
16+
}, method)
1517
model.init(tx, ty)
1618
model.fit()
1719

js/view/gaussian_process.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ var dispGaussianProcess = function (elm, platform) {
1414
platform.fit((tx, ty) => {
1515
ty = ty.map(v => v[0])
1616
if (!model) {
17-
model = new EnsembleBinaryModel(GaussianProcess, method, null, [kernel, beta])
17+
model = new EnsembleBinaryModel(function () {
18+
return new GaussianProcess(kernel, beta)
19+
}, method)
1820
model.init(tx, ty)
1921
}
2022
model.fit()

js/view/iellip.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@ var dispCELLIP = function (elm, platform) {
1111
if (type === 'CELLIP') {
1212
const gamma = +elm.select('[name=gamma]').property('value')
1313
const a = +elm.select('[name=a]').property('value')
14-
model = new EnsembleBinaryModel(CELLIP, method, null, [gamma, a])
14+
model = new EnsembleBinaryModel(function () {
15+
return new CELLIP(gamma, a)
16+
}, method)
1517
} else {
1618
const b = +elm.select('[name=b]').property('value')
1719
const c = +elm.select('[name=c]').property('value')
18-
model = new EnsembleBinaryModel(IELLIP, method, null, [b, c])
20+
model = new EnsembleBinaryModel(function () {
21+
return new IELLIP(b, c)
22+
}, method)
1923
}
2024
model.init(tx, ty)
2125
model.fit()

js/view/narow.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ var dispNAROW = function (elm, platform) {
77
const b = +elm.select('[name=b]').property('value')
88
platform.fit((tx, ty) => {
99
ty = ty.map(v => v[0])
10-
const model = new EnsembleBinaryModel(NAROW, method, null, [b])
10+
const model = new EnsembleBinaryModel(function () {
11+
return new NAROW(b)
12+
}, method)
1113
model.init(tx, ty)
1214
model.fit()
1315

js/view/normal_herd.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ var dispNormalHERD = function (elm, platform) {
88
const c = +elm.select('[name=c]').property('value')
99
platform.fit((tx, ty) => {
1010
ty = ty.map(v => v[0])
11-
const model = new EnsembleBinaryModel(NormalHERD, method, null, [type, c])
11+
const model = new EnsembleBinaryModel(function () {
12+
return new NormalHERD(type, c)
13+
}, method)
1214
model.init(tx, ty)
1315
model.fit()
1416

js/view/ogd.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ var dispOGD = function (elm, platform) {
88
platform.fit((tx, ty) => {
99
ty = ty.map(v => v[0])
1010
const c = +elm.select('[name=c]').property('value')
11-
const model = new EnsembleBinaryModel(OnlineGradientDescent, method, null, [c, loss])
11+
const model = new EnsembleBinaryModel(function () {
12+
return new OnlineGradientDescent(c, loss)
13+
}, method)
1214
model.init(tx, ty)
1315
model.fit()
1416

js/view/passive_aggressive.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ var dispPA = function (elm, platform) {
77
const version = +elm.select('[name=version]').property('value')
88
platform.fit((tx, ty) => {
99
ty = ty.map(v => v[0])
10-
const model = new EnsembleBinaryModel(PA, method, null, [version])
10+
const model = new EnsembleBinaryModel(function () {
11+
return new PA(version)
12+
}, method)
1113
model.init(tx, ty)
1214
model.fit()
1315

js/view/perceptron.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ var dispPerceptron = function (elm, platform) {
1010
platform.fit((tx, ty) => {
1111
ty = ty.map(v => v[0])
1212
if (!model) {
13-
model = new EnsembleBinaryModel(Perceptron, method, null, [average === 'average', rate])
13+
model = new EnsembleBinaryModel(function () {
14+
return new Perceptron(average === 'average', rate)
15+
}, method)
1416
model.init(tx, ty)
1517
}
1618
model.fit()

js/view/ridge.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@ var dispRidge = function (elm, platform) {
1616
if (task === 'CF') {
1717
const method = elm.select('[name=method]').property('value')
1818
if (kernelName) {
19-
model = new EnsembleBinaryModel(KernelRidge, method, null, [l, kernelName])
19+
model = new EnsembleBinaryModel(function () {
20+
return new KernelRidge(l, kernelName)
21+
}, method)
2022
} else {
21-
model = new EnsembleBinaryModel(Ridge, method, null, [l])
23+
model = new EnsembleBinaryModel(function () {
24+
return new Ridge(l)
25+
}, method)
2226
}
2327
} else {
2428
if (kernelName) {

js/view/sop.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ var dispSOP = function (elm, platform) {
77
platform.fit((tx, ty) => {
88
ty = ty.map(v => v[0])
99
const a = +elm.select('[name=a]').property('value')
10-
const model = new EnsembleBinaryModel(SecondOrderPerceptron, method, null, [a])
10+
const model = new EnsembleBinaryModel(function () {
11+
return new SecondOrderPerceptron(a)
12+
}, method)
1113
model.init(tx, ty)
1214
model.fit()
1315

js/view/svm.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ var dispSVM = function (elm, platform) {
6363
kernel_args.push(+elm.select('input[name=gamma]').property('value'))
6464
}
6565
const method = elm.select('[name=method]').property('value')
66-
model = new EnsembleBinaryModel(SVM, method, null, [kernel, kernel_args])
66+
model = new EnsembleBinaryModel(function () {
67+
return new SVM(kernel, kernel_args)
68+
}, method)
6769
platform.fit((tx, ty) => {
6870
model.init(
6971
tx,

lib/model/ensemble_binary.js

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,15 @@
99
*/
1010
export default class EnsembleBinaryModel {
1111
/**
12-
* @param {new (...args: *[]) => BinaryModel} model Binary model
12+
* @param {new () => BinaryModel} model Binary model
1313
* @param {'oneone' | 'onerest'} type
1414
* @param {*[]} [classes]
15-
* @param {*[]} [init_args]
1615
*/
17-
constructor(model, type, classes, init_args) {
16+
constructor(model, type, classes) {
1817
if (type === 'oneone') {
19-
return new OneVsOneModel(model, classes, init_args)
18+
return new OneVsOneModel(model, classes)
2019
} else if (type === 'onerest') {
21-
return new OneVsRestModel(model, classes, init_args)
20+
return new OneVsRestModel(model, classes)
2221
}
2322
return null
2423
}
@@ -59,19 +58,18 @@ const argmax = function (arr, key) {
5958

6059
class OneVsRestModel {
6160
// one vs rest
62-
constructor(model, classes, init_args) {
61+
constructor(model, classes) {
6362
if (classes && !Array.isArray(classes)) {
6463
classes = [...classes]
6564
}
6665
this._modelcls = model
6766
this._classes = classes
6867
this._model = []
6968
this._n = 0
70-
this._init_args = init_args || []
7169
if (classes) {
7270
this._n = classes.length
7371
for (let i = 0; i < this._n; i++) {
74-
this._model[i] = new model(...this._init_args)
72+
this._model[i] = new model()
7573
}
7674
}
7775
}
@@ -82,7 +80,7 @@ class OneVsRestModel {
8280
this._classes = [...new Set(train_y)]
8381
this._n = this._classes.length
8482
for (let i = 0; i < this._n; i++) {
85-
this._model[i] = new this._modelcls(...this._init_args)
83+
this._model[i] = new this._modelcls()
8684
}
8785
}
8886
for (let i = 0; i < this._n; i++) {
@@ -123,21 +121,20 @@ class OneVsRestModel {
123121

124122
class OneVsOneModel {
125123
// one vs one
126-
constructor(model, classes, init_args) {
124+
constructor(model, classes) {
127125
if (classes && !Array.isArray(classes)) {
128126
classes = [...classes]
129127
}
130128
this._modelcls = model
131129
this._classes = classes
132130
this._model = []
133131
this._n = 0
134-
this._init_args = init_args || []
135132
if (classes) {
136133
this._n = classes.length
137134
for (let i = 0; i < this._n; i++) {
138135
this._model[i] = []
139136
for (let j = 0; j < i; j++) {
140-
this._model[i][j] = new model(...this._init_args)
137+
this._model[i][j] = new model()
141138
}
142139
}
143140
}
@@ -151,7 +148,7 @@ class OneVsOneModel {
151148
for (let i = 0; i < this._n; i++) {
152149
this._model[i] = []
153150
for (let j = 0; j < i; j++) {
154-
this._model[i][j] = new this._modelcls(...this._init_args)
151+
this._model[i][j] = new this._modelcls()
155152
}
156153
}
157154
}

tests/gui/view/adaline.test.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import puppeteer from 'puppeteer'
2+
3+
/** @type {puppeteer.Browser} */
4+
let browser
5+
beforeAll(async () => {
6+
browser = await puppeteer.launch({ args: ['--no-sandbox'] })
7+
})
8+
9+
afterAll(async () => {
10+
await browser.close()
11+
})
12+
13+
describe('classification', () => {
14+
/** @type {puppeteer.Page} */
15+
let page
16+
beforeEach(async () => {
17+
page = await browser.newPage()
18+
await page.goto(`http://${process.env.SERVER_HOST}/`)
19+
page.on('console', message => console.log(`${message.type().substring(0, 3).toUpperCase()} ${message.text()}`))
20+
.on('pageerror', ({ message }) => console.log(message))
21+
.on('requestfailed', request => console.log(`${request.failure().errorText} ${request.url()}`))
22+
await page.waitForSelector('#data_menu > *')
23+
}, 10000)
24+
25+
test('initialize', async () => {
26+
const taskSelectBox = await page.waitForSelector('#ml_selector dl:first-child dd:nth-child(5) select')
27+
taskSelectBox.select('CF')
28+
const modelSelectBox = await page.waitForSelector('#ml_selector .model_selection #mlDisp')
29+
modelSelectBox.select('adaline')
30+
const methodMenu = await page.waitForSelector('#ml_selector #method_menu')
31+
const buttons = await methodMenu.waitForSelector('.buttons')
32+
33+
const methods = await buttons.waitForSelector('[name=method]')
34+
await expect((await methods.getProperty('value')).jsonValue()).resolves.toBe('oneone')
35+
const rate = await buttons.waitForSelector('[name=rate]')
36+
await expect((await rate.getProperty('value')).jsonValue()).resolves.toBe('0.1')
37+
const epoch = await buttons.waitForSelector('[name=epoch]')
38+
await expect(epoch.evaluate(el => el.textContent)).resolves.toBe('0')
39+
}, 10000)
40+
41+
test('learn', async () => {
42+
const taskSelectBox = await page.waitForSelector('#ml_selector dl:first-child dd:nth-child(5) select')
43+
taskSelectBox.select('CF')
44+
const modelSelectBox = await page.waitForSelector('#ml_selector .model_selection #mlDisp')
45+
modelSelectBox.select('adaline')
46+
const methodMenu = await page.waitForSelector('#ml_selector #method_menu')
47+
const buttons = await methodMenu.waitForSelector('.buttons')
48+
49+
const epoch = await buttons.waitForSelector('[name=epoch]')
50+
await expect(epoch.evaluate(el => el.textContent)).resolves.toBe('0')
51+
const methodFooter = await page.waitForSelector('#method_footer')
52+
await expect(methodFooter.evaluate(el => el.textContent)).resolves.toBe('')
53+
54+
const initButton = await buttons.waitForSelector('input[value=Initialize]')
55+
await initButton.evaluate(el => el.click())
56+
const stepButton = await buttons.waitForSelector('input[value=Step]:enabled')
57+
await stepButton.evaluate(el => el.click())
58+
59+
await expect(epoch.evaluate(el => el.textContent)).resolves.toBe('1')
60+
await expect(methodFooter.evaluate(el => el.textContent)).resolves.toMatch(/^Accuracy:[0-9.]+$/)
61+
}, 10000)
62+
})

tests/gui/view/alma.test.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import puppeteer from 'puppeteer'
2+
3+
/** @type {puppeteer.Browser} */
4+
let browser
5+
beforeAll(async () => {
6+
browser = await puppeteer.launch({ args: ['--no-sandbox'] })
7+
})
8+
9+
afterAll(async () => {
10+
await browser.close()
11+
})
12+
13+
describe('classification', () => {
14+
/** @type {puppeteer.Page} */
15+
let page
16+
beforeEach(async () => {
17+
page = await browser.newPage()
18+
await page.goto(`http://${process.env.SERVER_HOST}/`)
19+
page.on('console', message => console.log(`${message.type().substring(0, 3).toUpperCase()} ${message.text()}`))
20+
.on('pageerror', ({ message }) => console.log(message))
21+
.on('requestfailed', request => console.log(`${request.failure().errorText} ${request.url()}`))
22+
await page.waitForSelector('#data_menu > *')
23+
}, 10000)
24+
25+
test('initialize', async () => {
26+
const taskSelectBox = await page.waitForSelector('#ml_selector dl:first-child dd:nth-child(5) select')
27+
taskSelectBox.select('CF')
28+
const modelSelectBox = await page.waitForSelector('#ml_selector .model_selection #mlDisp')
29+
modelSelectBox.select('alma')
30+
const methodMenu = await page.waitForSelector('#ml_selector #method_menu')
31+
const buttons = await methodMenu.waitForSelector('.buttons')
32+
33+
const methods = await buttons.waitForSelector('[name=method]')
34+
await expect((await methods.getProperty('value')).jsonValue()).resolves.toBe('oneone')
35+
const p = await buttons.waitForSelector('[name=p]')
36+
await expect((await p.getProperty('value')).jsonValue()).resolves.toBe('2')
37+
const alpha = await buttons.waitForSelector('[name=alpha]')
38+
await expect((await alpha.getProperty('value')).jsonValue()).resolves.toBe('1')
39+
const b = await buttons.waitForSelector('[name=b]')
40+
await expect((await b.getProperty('value')).jsonValue()).resolves.toBe('1')
41+
const c = await buttons.waitForSelector('[name=c]')
42+
await expect((await c.getProperty('value')).jsonValue()).resolves.toBe('1')
43+
}, 10000)
44+
45+
test('learn', async () => {
46+
const taskSelectBox = await page.waitForSelector('#ml_selector dl:first-child dd:nth-child(5) select')
47+
taskSelectBox.select('CF')
48+
const modelSelectBox = await page.waitForSelector('#ml_selector .model_selection #mlDisp')
49+
modelSelectBox.select('alma')
50+
const methodMenu = await page.waitForSelector('#ml_selector #method_menu')
51+
const buttons = await methodMenu.waitForSelector('.buttons')
52+
53+
const methodFooter = await page.waitForSelector('#method_footer')
54+
await expect(methodFooter.evaluate(el => el.textContent)).resolves.toBe('')
55+
56+
const calculateButton = await buttons.waitForSelector('input[value=Calculate]')
57+
await calculateButton.evaluate(el => el.click())
58+
59+
await expect(methodFooter.evaluate(el => el.textContent)).resolves.toMatch(/^Accuracy:[0-9.]+$/)
60+
}, 10000)
61+
})

0 commit comments

Comments
 (0)