From 65386bf742a394e1ccbcaf5ca746984f194c1d34 Mon Sep 17 00:00:00 2001 From: Cesar Anton Dorantes Date: Tue, 13 Mar 2018 14:27:02 -0400 Subject: [PATCH] Neuron.js JS Heap refactoring WIP https://github.com/cazala/synaptic/issues/307#issuecomment-371711086 --- package-lock.json | 324 +++++++++------ src/Neuron.js | 993 ++++++++++++++++++++++++++-------------------- 2 files changed, 767 insertions(+), 550 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5292ed9..8a30668 100644 --- a/package-lock.json +++ b/package-lock.json @@ -172,11 +172,6 @@ "util": "0.10.3" } }, - "assertion-error": { - "version": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", - "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", - "dev": true - }, "async": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", @@ -1336,17 +1331,50 @@ } }, "chai": { - "version": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", "dev": true, "requires": { - "assertion-error": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", - "deep-eql": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", - "type-detect": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz" + "assertion-error": "1.1.0", + "deep-eql": "0.1.3", + "type-detect": "1.0.0" + }, + "dependencies": { + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dev": true, + "requires": { + "type-detect": "0.1.1" + }, + "dependencies": { + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", + "dev": true + } + } + }, + "type-detect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", + "dev": true + } } }, "chai-stats": { - "version": "https://registry.npmjs.org/chai-stats/-/chai-stats-0.3.0.tgz", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/chai-stats/-/chai-stats-0.3.0.tgz", "integrity": "sha1-pd38c2vX0Z7cr/+s/3s4VFRrIFY=", "dev": true }, @@ -1444,11 +1472,6 @@ } } }, - "commander": { - "version": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", - "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", - "dev": true - }, "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", @@ -1667,21 +1690,6 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, - "deep-eql": { - "version": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", - "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", - "dev": true, - "requires": { - "type-detect": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz" - }, - "dependencies": { - "type-detect": { - "version": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", - "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", - "dev": true - } - } - }, "depd": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", @@ -1712,11 +1720,6 @@ "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", "dev": true }, - "diff": { - "version": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", - "dev": true - }, "diffie-hellman": { "version": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=", @@ -3254,14 +3257,6 @@ } } }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, "string-width": { "version": "1.0.2", "bundled": true, @@ -3272,6 +3267,14 @@ "strip-ansi": "3.0.1" } }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, "stringstream": { "version": "0.0.5", "bundled": true, @@ -3410,6 +3413,24 @@ } } }, + "glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "minimatch": "0.3.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, "glob-base": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", @@ -3441,11 +3462,6 @@ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, - "growl": { - "version": "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz", - "integrity": "sha1-Sy3sjZB+k9szZiTc7AGDUC+MlCg=", - "dev": true - }, "har-schema": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", @@ -3751,27 +3767,6 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, - "jade": { - "version": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", - "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", - "dev": true, - "requires": { - "commander": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz" - }, - "dependencies": { - "commander": { - "version": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", - "dev": true - }, - "mkdirp": { - "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", - "dev": true - } - } - }, "jodid25519": { "version": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz", "integrity": "sha1-BtSRIlUJNBlHfUJWM2BuDpB4KWc=", @@ -4163,11 +4158,6 @@ "js-tokens": "3.0.2" } }, - "lru-cache": { - "version": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, "make-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.0.0.tgz", @@ -4249,6 +4239,30 @@ "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=", "dev": true }, + "minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "dev": true, + "requires": { + "lru-cache": "2.7.3", + "sigmund": "1.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + } + } + }, "minimist": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", @@ -4271,52 +4285,104 @@ } }, "mocha": { - "version": "https://registry.npmjs.org/mocha/-/mocha-2.4.5.tgz", - "integrity": "sha1-FRdo3Sh161G8gpXpgAAm6fK7OY8=", - "dev": true, - "requires": { - "commander": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", - "debug": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "diff": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "glob": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz", - "growl": "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz", - "jade": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", - "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz" + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", + "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", + "dev": true, + "requires": { + "commander": "2.3.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.2", + "glob": "3.2.11", + "growl": "1.9.2", + "jade": "0.26.3", + "mkdirp": "0.5.1", + "supports-color": "1.2.0", + "to-iso-string": "0.0.2" }, "dependencies": { + "commander": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", + "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", + "dev": true + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "dev": true + }, "escape-string-regexp": { - "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", "dev": true }, - "glob": { - "version": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz", - "integrity": "sha1-4xPusknHr/qlxHUoaw4RW1mDlGc=", + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "jade": { + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", + "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", "dev": true, "requires": { - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz" + "commander": "0.6.1", + "mkdirp": "0.3.0" + }, + "dependencies": { + "commander": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", + "dev": true + }, + "mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", + "dev": true + } } }, - "graceful-fs": { - "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", - "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, - "minimatch": { - "version": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { - "lru-cache": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "sigmund": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz" + "minimist": "0.0.8" } }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, "supports-color": { - "version": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", "dev": true } @@ -4852,11 +4918,20 @@ } }, "pre-push": { - "version": "https://registry.npmjs.org/pre-push/-/pre-push-0.1.1.tgz", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pre-push/-/pre-push-0.1.1.tgz", "integrity": "sha1-Kip5gn0kOnbJEImJescH9F5xaqw=", "dev": true, "requires": { - "shelljs": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz" + "shelljs": "0.3.0" + }, + "dependencies": { + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + } } }, "preserve": { @@ -5243,16 +5318,6 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "shelljs": { - "version": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", - "dev": true - }, - "sigmund": { - "version": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", @@ -5498,15 +5563,6 @@ "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" } }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, "string-width": { "version": "https://registry.npmjs.org/string-width/-/string-width-1.0.1.tgz", "integrity": "sha1-ySEptvHX9SrPmvQkom44ZKBc6wo=", @@ -5517,6 +5573,15 @@ "strip-ansi": "3.0.1" } }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, "stringstream": { "version": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", @@ -5591,6 +5656,12 @@ "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", "dev": true }, + "to-iso-string": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", + "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", + "dev": true + }, "tough-cookie": { "version": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.1.tgz", "integrity": "sha1-mcd9+7fYBCSeiimdTLD9gf7wg/0=", @@ -5614,11 +5685,6 @@ "dev": true, "optional": true }, - "type-detect": { - "version": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", - "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", - "dev": true - }, "type-is": { "version": "1.6.15", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", diff --git a/src/Neuron.js b/src/Neuron.js index c854ce4..ddd62d7 100644 --- a/src/Neuron.js +++ b/src/Neuron.js @@ -1,3 +1,5 @@ +'use strict'; + import Connection, {connections} from './Connection'; let neurons = 0; @@ -6,33 +8,37 @@ let neurons = 0; const squash = { // eq. 5 & 5' LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); if (!derivate) - return fx; - return fx * (1 - fx); + return 1 / (1 + Math.exp(-x)); + else + return 1 / (1 + Math.exp(-x)) * (1 - 1 / (1 + Math.exp(-x))); }, + TANH: function (x, derivate) { if (derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); + return 1 - Math.pow(Math.tanh(x), 2); + else + return Math.tanh(x); }, + IDENTITY: function (x, derivate) { return derivate ? 1 : x; }, + HLIM: function (x, derivate) { return derivate ? 1 : x > 0 ? 1 : 0; }, + RELU: function (x, derivate) { if (derivate) return x > 0 ? 1 : 0; - return x > 0 ? x : 0; + else + return x > 0 ? x : 0; } }; export default class Neuron { - static squash = squash; - constructor() { this.ID = Neuron.uid(); @@ -41,16 +47,19 @@ export default class Neuron { projected: {}, gated: {} }; + this.error = { responsibility: 0, projected: 0, gated: 0 }; + this.trace = { elegibility: {}, extended: {}, influences: {} }; + this.state = 0; this.old = 0; this.activation = 0; @@ -60,6 +69,8 @@ export default class Neuron { this.bias = Math.random() * .2 - .1; } + static squash = squash; + // activate the neuron activate(input) { // activation from enviroment (for input neurons) @@ -67,6 +78,7 @@ export default class Neuron { this.activation = input; this.derivative = 0; this.bias = 0; + return this.activation; } @@ -77,9 +89,9 @@ export default class Neuron { this.state = this.selfconnection.gain * this.selfconnection.weight * this.state + this.bias; - for (var i in this.connections.inputs) { - var input = this.connections.inputs[i]; - this.state += input.from.activation * input.weight * input.gain; + for (this._i in this.connections.inputs) { + this._input = this.connections.inputs[this._i]; + this.state += this._input.from.activation * this._input.weight * this._input.gain; } // eq. 16 @@ -89,46 +101,42 @@ export default class Neuron { this.derivative = this.squash(this.state, true); // update traces - var influences = []; - for (var id in this.trace.extended) { + this._influences = []; + for (this._id in this.trace.extended) { // extended elegibility trace - var neuron = this.neighboors[id]; + this._neuron = this.neighboors[this._id]; // if gated neuron's selfconnection is gated by this unit, the influence keeps track of the neuron's old state - var influence = neuron.selfconnection.gater == this ? neuron.old : 0; + this._influence = this._neuron.selfconnection.gater == this ? this._neuron.old : 0; // index runs over all the incoming connections to the gated neuron that are gated by this unit - for (var incoming in this.trace.influences[neuron.ID]) { // captures the effect that has an input connection to this unit, on a neuron that is gated by this unit - influence += this.trace.influences[neuron.ID][incoming].weight * - this.trace.influences[neuron.ID][incoming].from.activation; + for (this._incoming in this.trace.influences[this._neuron.ID]) { // captures the effect that has an input connection to this unit, on a neuron that is gated by this unit + this._influence += this.trace.influences[this._neuron.ID][this._incoming].weight * this.trace.influences[this._neuron.ID][this._incoming].from.activation; } - influences[neuron.ID] = influence; + + this._influences[this._neuron.ID] = this._influence; } - for (var i in this.connections.inputs) { - var input = this.connections.inputs[i]; + for (this._i in this.connections.inputs) { + this._input = this.connections.inputs[this._i]; // elegibility trace - Eq. 17 - this.trace.elegibility[input.ID] = this.selfconnection.gain * this.selfconnection - .weight * this.trace.elegibility[input.ID] + input.gain * input.from - .activation; + this.trace.elegibility[this._input.ID] = this.selfconnection.gain * this.selfconnection.weight * this.trace.elegibility[this._input.ID] + this._input.gain * this._input.from.activation; - for (var id in this.trace.extended) { + for (this._id in this.trace.extended) { // extended elegibility trace - var xtrace = this.trace.extended[id]; - var neuron = this.neighboors[id]; - var influence = influences[neuron.ID]; + this._xtrace = this.trace.extended[this._id]; + this._neuron = this.neighboors[this._id]; + this._influence = this._influences[this._neuron.ID]; // eq. 18 - xtrace[input.ID] = neuron.selfconnection.gain * neuron.selfconnection - .weight * xtrace[input.ID] + this.derivative * this.trace.elegibility[ - input.ID] * influence; + this._xtrace[this._input.ID] = this._neuron.selfconnection.gain * this._neuron.selfconnection.weight * this._xtrace[this._input.ID] + this.derivative * this.trace.elegibility[this._input.ID] * this._influence; } } // update gated connection's gains - for (var connection in this.connections.gated) { - this.connections.gated[connection].gain = this.activation; + for (this._connection in this.connections.gated) { + this.connections.gated[this._connection].gain = this.activation; } return this.activation; @@ -137,45 +145,40 @@ export default class Neuron { // back-propagate the error propagate(rate, target) { // error accumulator - var error = 0; - - // whether or not this neuron is in the output layer - var isOutput = typeof target != 'undefined'; + this._errorCount = 0; // output neurons get their error from the enviroment - if (isOutput) + if (typeof target != 'undefined') // whether or not this neuron is in the output layer this.error.responsibility = this.error.projected = target - this.activation; // Eq. 10 - - else // the rest of the neuron compute their error responsibilities by backpropagation - { + else { // the rest of the neuron compute their error responsibilities by backpropagation // error responsibilities from all the connections projected from this neuron - for (var id in this.connections.projected) { - var connection = this.connections.projected[id]; - var neuron = connection.to; + for (this._id in this.connections.projected) { + this._connection = this.connections.projected[this._id]; + this._neuron = this._connection.to; // Eq. 21 - error += neuron.error.responsibility * connection.gain * connection.weight; + this._errorCount += this._neuron.error.responsibility * this._connection.gain * this._connection.weight; } // projected error responsibility - this.error.projected = this.derivative * error; + this.error.projected = this.derivative * this._errorCount; - error = 0; + this._errorCount = 0; // error responsibilities from all the connections gated by this neuron - for (var id in this.trace.extended) { - var neuron = this.neighboors[id]; // gated neuron - var influence = neuron.selfconnection.gater == this ? neuron.old : 0; // if gated neuron's selfconnection is gated by this neuron + for (this._id in this.trace.extended) { + this._neuron = this.neighboors[this._id]; // gated neuron + this._influence = this._neuron.selfconnection.gater == this ? this._neuron.old : 0; // if gated neuron's selfconnection is gated by this neuron // index runs over all the connections to the gated neuron that are gated by this neuron - for (var input in this.trace.influences[id]) { // captures the effect that the input connection of this neuron have, on a neuron which its input/s is/are gated by this neuron - influence += this.trace.influences[id][input].weight * this.trace.influences[ - neuron.ID][input].from.activation; + for (this._input in this.trace.influences[this._id]) { // captures the effect that the input connection of this neuron have, on a neuron which its input/s is/are gated by this neuron + this._influence += this.trace.influences[this._id][this._input].weight * this.trace.influences[ + this._neuron.ID][this._input].from.activation; } // eq. 22 - error += neuron.error.responsibility * influence; + this._errorCount += this._neuron.error.responsibility * this._influence; } // gated error responsibility - this.error.gated = this.derivative * error; + this.error.gated = this.derivative * this._errorCount; // error responsibility - Eq. 23 this.error.responsibility = this.error.projected + this.error.gated; @@ -185,17 +188,16 @@ export default class Neuron { rate = rate || .1; // adjust all the neuron's incoming connections - for (var id in this.connections.inputs) { - var input = this.connections.inputs[id]; + for (this._id in this.connections.inputs) { + this._input = this.connections.inputs[this._id]; // Eq. 24 - var gradient = this.error.projected * this.trace.elegibility[input.ID]; - for (var id in this.trace.extended) { - var neuron = this.neighboors[id]; - gradient += neuron.error.responsibility * this.trace.extended[ - neuron.ID][input.ID]; + this._gradient = this.error.projected * this.trace.elegibility[this._input.ID]; + for (this._i in this.trace.extended) { + this._neuron = this.neighboors[this._i]; + this._gradient += this._neuron.error.responsibility * this.trace.extended[this._neuron.ID][this._input.ID]; } - input.weight += rate * gradient; // adjust weights - aka learn + this._input.weight += rate * this._gradient; // adjust weights - aka learn } // adjust bias @@ -210,52 +212,53 @@ export default class Neuron { } // check if connection already exists - var connected = this.connected(neuron); - if (connected && connected.type == 'projected') { + this._connected = this.connected(neuron); + if (this._connected && this._connected.type == 'projected') { // update connection if (typeof weight != 'undefined') - connected.connection.weight = weight; + this._connected.connection.weight = weight; // return existing connection - return connected.connection; + return this._connected.connection; } else { // create a new connection - var connection = new Connection(this, neuron, weight); + this._connection = new Connection(this, neuron, weight); } // reference all the connections and traces - this.connections.projected[connection.ID] = connection; + this.connections.projected[this._connection.ID] = this._connection; this.neighboors[neuron.ID] = neuron; - neuron.connections.inputs[connection.ID] = connection; - neuron.trace.elegibility[connection.ID] = 0; + neuron.connections.inputs[this._connection.ID] = this._connection; + neuron.trace.elegibility[this._connection.ID] = 0; - for (var id in neuron.trace.extended) { - var trace = neuron.trace.extended[id]; - trace[connection.ID] = 0; + for (this._id in neuron.trace.extended) { + this._trace = neuron.trace.extended[this._id]; + this._trace[this._connection.ID] = 0; } - return connection; + return this._connection; } gate(connection) { // add connection to gated list this.connections.gated[connection.ID] = connection; - var neuron = connection.to; - if (!(neuron.ID in this.trace.extended)) { + this._neuron = connection.to; + if (!(this._neuron.ID in this.trace.extended)) { // extended trace - this.neighboors[neuron.ID] = neuron; - var xtrace = this.trace.extended[neuron.ID] = {}; - for (var id in this.connections.inputs) { - var input = this.connections.inputs[id]; - xtrace[input.ID] = 0; + this.neighboors[this._neuron.ID] = this._neuron; + this._xtrace = this.trace.extended[this._neuron.ID] = {}; + + for (this._id in this.connections.inputs) { + this._input = this.connections.inputs[this._id]; + this._xtrace[this._input.ID] = 0; } } // keep track - if (neuron.ID in this.trace.influences) - this.trace.influences[neuron.ID].push(connection); + if (this._neuron.ID in this.trace.influences) + this.trace.influences[this._neuron.ID].push(connection); else - this.trace.influences[neuron.ID] = [connection]; + this.trace.influences[this._neuron.ID] = [connection]; // set gater connection.gater = this; @@ -268,32 +271,40 @@ export default class Neuron { // returns true or false whether the neuron is connected to another neuron (parameter) connected(neuron) { - var result = { + this._result = { type: null, connection: false }; if (this == neuron) { if (this.selfconnected()) { - result.type = 'selfconnection'; - result.connection = this.selfconnection; - return result; + this._result.type = 'selfconnection'; + this._result.connection = this.selfconnection; + + return this._result; + } else + return false; } - for (var type in this.connections) { - for (var connection in this.connections[type]) { - var connection = this.connections[type][connection]; - if (connection.to == neuron) { - result.type = type; - result.connection = connection; - return result; - } else if (connection.from == neuron) { - result.type = type; - result.connection = connection; - return result; - } + for (this._type in this.connections) { + for (this._i in this.connections[this._type]) { + this._connection = this.connections[this._type][this._i]; + + switch (true) { + case (this._connection.to == neuron) : + this._result.type = this._type; + this._result.connection = this._connection; + + return this._result; + + case (this._connection.from == neuron) : + this._result.type = this._type; + this._result.connection = this._connection; + + return this._result; + } } } @@ -302,13 +313,13 @@ export default class Neuron { // clears all the traces (the neuron forgets it's context, but the connections remain intact) clear() { - for (var trace in this.trace.elegibility) { - this.trace.elegibility[trace] = 0; + for (this._trace in this.trace.elegibility) { + this.trace.elegibility[this._trace] = 0; } - for (var trace in this.trace.extended) { - for (var extended in this.trace.extended[trace]) { - this.trace.extended[trace][extended] = 0; + for (this._trace in this.trace.extended) { + for (this._extended in this.trace.extended[this._trace]) { + this.trace.extended[this._trace][this._extended] = 0; } } @@ -319,9 +330,9 @@ export default class Neuron { reset() { this.clear(); - for (var type in this.connections) { - for (var connection in this.connections[type]) { - this.connections[type][connection].weight = Math.random() * .2 - .1; + for (this._type in this.connections) { + for (this._connection in this.connections[this._type]) { + this.connections[this._type][this._connection].weight = Math.random() * .2 - .1; } } @@ -333,193 +344,124 @@ export default class Neuron { optimize(optimized, layer) { optimized = optimized || {}; - var store_activation = []; - var store_trace = []; - var store_propagation = []; - var varID = optimized.memory || 0; - var neurons = optimized.neurons || 1; - var inputs = optimized.inputs || []; - var targets = optimized.targets || []; - var outputs = optimized.outputs || []; - var variables = optimized.variables || {}; - var activation_sentences = optimized.activation_sentences || []; - var trace_sentences = optimized.trace_sentences || []; - var propagation_sentences = optimized.propagation_sentences || []; - var layers = optimized.layers || {__count: 0, __neuron: 0}; - - // allocate sentences - var allocate = function (store) { - var allocated = layer in layers && store[layers.__count]; - if (!allocated) { - layers.__count = store.push([]) - 1; - layers[layer] = layers.__count; - } - }; - allocate(activation_sentences); - allocate(trace_sentences); - allocate(propagation_sentences); - var currentLayer = layers.__count; - - // get/reserve space in memory by creating a unique ID for a variablel - var getVar = function () { - var args = Array.prototype.slice.call(arguments); - - if (args.length == 1) { - if (args[0] == 'target') { - var id = 'target_' + targets.length; - targets.push(varID); - } else - var id = args[0]; - if (id in variables) - return variables[id]; - return variables[id] = { - value: 0, - id: varID++ - }; - } else { - var extended = args.length > 2; - if (extended) - var value = args.pop(); - - var unit = args.shift(); - var prop = args.pop(); - - if (!extended) - var value = unit[prop]; - - var id = prop + '_'; - for (var i = 0; i < args.length; i++) - id += args[i] + '_'; - id += unit.ID; - if (id in variables) - return variables[id]; - - return variables[id] = { - value: value, - id: varID++ - }; - } - }; - - // build sentence - var buildSentence = function () { - var args = Array.prototype.slice.call(arguments); - var store = args.pop(); - var sentence = ''; - for (var i = 0; i < args.length; i++) - if (typeof args[i] == 'string') - sentence += args[i]; - else - sentence += 'F[' + args[i].id + ']'; - - store.push(sentence + ';'); - }; - - // helper to check if an object is empty - var isEmpty = function (obj) { - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) - return false; - } - return true; - }; + this._varID = optimized.memory || 0; + + this._store_activation = []; + this._store_trace = []; + this._store_propagation = []; + this._inputs = optimized.inputs || []; + this._targets = optimized.targets || []; + this._outputs = optimized.outputs || []; + this._variables = optimized.variables || {}; + this._activation_sentences = optimized.activation_sentences || []; + this._trace_sentences = optimized.trace_sentences || []; + this._propagation_sentences = optimized.propagation_sentences || []; + this._layers = optimized.layers || {__count: 0, __neuron: 0}; + + this.allocate(layer, this._activation_sentences); + this.allocate(layer, this._trace_sentences); + this.allocate(layer, this._propagation_sentences); + this._currentLayer = this._layers.__count; // characteristics of the neuron - var noProjections = isEmpty(this.connections.projected); - var noGates = isEmpty(this.connections.gated); - var isInput = layer == 'input' ? true : isEmpty(this.connections.inputs); - var isOutput = layer == 'output' ? true : noProjections && noGates; + this._noProjections = this.isEmpty(this.connections.projected); + this._noGates = this.isEmpty(this.connections.gated); + var isInput = layer == 'input' ? true : this.isEmpty(this.connections.inputs); + var isOutput = layer == 'output' ? true : this._noProjections && this._noGates; // optimize neuron's behaviour - var rate = getVar('rate'); - var activation = getVar(this, 'activation'); + var rate = this.getVar('rate'); + var activation = this.getVar(this, 'activation'); if (isInput) - inputs.push(activation.id); + this._inputs.push(activation.id); else { - activation_sentences[currentLayer].push(store_activation); - trace_sentences[currentLayer].push(store_trace); - propagation_sentences[currentLayer].push(store_propagation); - var old = getVar(this, 'old'); - var state = getVar(this, 'state'); - var bias = getVar(this, 'bias'); + this._activation_sentences[this._currentLayer].push(this._store_activation); + this._trace_sentences[this._currentLayer].push(this._store_trace); + this._propagation_sentences[this._currentLayer].push(this._store_propagation); + var old = this.getVar(this, 'old'); + var state = this.getVar(this, 'state'); + var bias = this.getVar(this, 'bias'); if (this.selfconnection.gater) - var self_gain = getVar(this.selfconnection, 'gain'); + var self_gain = this.getVar(this.selfconnection, 'gain'); if (this.selfconnected()) - var self_weight = getVar(this.selfconnection, 'weight'); - buildSentence(old, ' = ', state, store_activation); + var self_weight = this.getVar(this.selfconnection, 'weight'); + this.buildSentence(old, ' = ', state, this._store_activation); if (this.selfconnected()) if (this.selfconnection.gater) - buildSentence(state, ' = ', self_gain, ' * ', self_weight, ' * ', - state, ' + ', bias, store_activation); + this.buildSentence(state, ' = ', self_gain, ' * ', self_weight, ' * ', + state, ' + ', bias, this._store_activation); else - buildSentence(state, ' = ', self_weight, ' * ', state, ' + ', - bias, store_activation); + this.buildSentence(state, ' = ', self_weight, ' * ', state, ' + ', + bias, this._store_activation); else - buildSentence(state, ' = ', bias, store_activation); + this.buildSentence(state, ' = ', bias, this._store_activation); for (var i in this.connections.inputs) { var input = this.connections.inputs[i]; - var input_activation = getVar(input.from, 'activation'); - var input_weight = getVar(input, 'weight'); + var input_activation = this.getVar(input.from, 'activation'); + var input_weight = this.getVar(input, 'weight'); if (input.gater) - var input_gain = getVar(input, 'gain'); + var input_gain = this.getVar(input, 'gain'); if (this.connections.inputs[i].gater) - buildSentence(state, ' += ', input_activation, ' * ', - input_weight, ' * ', input_gain, store_activation); + this.buildSentence(state, ' += ', input_activation, ' * ', + input_weight, ' * ', input_gain, this._store_activation); else - buildSentence(state, ' += ', input_activation, ' * ', - input_weight, store_activation); + this.buildSentence(state, ' += ', input_activation, ' * ', + input_weight, this._store_activation); } - var derivative = getVar(this, 'derivative'); + var derivative = this.getVar(this, 'derivative'); + switch (this.squash) { case Neuron.squash.LOGISTIC: - buildSentence(activation, ' = (1 / (1 + Math.exp(-', state, ')))', - store_activation); - buildSentence(derivative, ' = ', activation, ' * (1 - ', - activation, ')', store_activation); + this.buildSentence(activation, ' = (1 / (1 + Math.exp(-', state, ')))', + this._store_activation); + this.buildSentence(derivative, ' = ', activation, ' * (1 - ', + activation, ')', this._store_activation); break; + case Neuron.squash.TANH: - var eP = getVar('aux'); - var eN = getVar('aux_2'); - buildSentence(eP, ' = Math.exp(', state, ')', store_activation); - buildSentence(eN, ' = 1 / ', eP, store_activation); - buildSentence(activation, ' = (', eP, ' - ', eN, ') / (', eP, ' + ', eN, ')', store_activation); - buildSentence(derivative, ' = 1 - (', activation, ' * ', activation, ')', store_activation); + var eP = this.getVar('aux'); + var eN = this.getVar('aux_2'); + this.buildSentence(eP, ' = Math.exp(', state, ')', this._store_activation); + this.buildSentence(eN, ' = 1 / ', eP, this._store_activation); + this.buildSentence(activation, ' = (', eP, ' - ', eN, ') / (', eP, ' + ', eN, ')', this._store_activation); + this.buildSentence(derivative, ' = 1 - (', activation, ' * ', activation, ')', this._store_activation); break; + case Neuron.squash.IDENTITY: - buildSentence(activation, ' = ', state, store_activation); - buildSentence(derivative, ' = 1', store_activation); + this.buildSentence(activation, ' = ', state, this._store_activation); + this.buildSentence(derivative, ' = 1', this._store_activation); break; + case Neuron.squash.HLIM: - buildSentence(activation, ' = +(', state, ' > 0)', store_activation); - buildSentence(derivative, ' = 1', store_activation); + this.buildSentence(activation, ' = +(', state, ' > 0)', this._store_activation); + this.buildSentence(derivative, ' = 1', this._store_activation); break; + case Neuron.squash.RELU: - buildSentence(activation, ' = ', state, ' > 0 ? ', state, ' : 0', store_activation); - buildSentence(derivative, ' = ', state, ' > 0 ? 1 : 0', store_activation); + this.buildSentence(activation, ' = ', state, ' > 0 ? ', state, ' : 0', this._store_activation); + this.buildSentence(derivative, ' = ', state, ' > 0 ? 1 : 0', this._store_activation); break; } for (var id in this.trace.extended) { // calculate extended elegibility traces in advance - var neuron = this.neighboors[id]; - var influence = getVar('influences[' + neuron.ID + ']'); - var neuron_old = getVar(neuron, 'old'); - var initialized = false; - if (neuron.selfconnection.gater == this) { - buildSentence(influence, ' = ', neuron_old, store_trace); - initialized = true; + this._neuron = this.neighboors[id]; + this._influence = this.getVar('influences[' + this._neuron.ID + ']'); + this._neuron_old = this.getVar(this._neuron, 'old'); + this._initialized = false; + if (this._neuron.selfconnection.gater == this) { + this.buildSentence(this._influence, ' = ', this._neuron_old, this._store_trace); + this._initialized = true; } - for (var incoming in this.trace.influences[neuron.ID]) { - var incoming_weight = getVar(this.trace.influences[neuron.ID] - [incoming], 'weight'); - var incoming_activation = getVar(this.trace.influences[neuron.ID] - [incoming].from, 'activation'); - - if (initialized) - buildSentence(influence, ' += ', incoming_weight, ' * ', incoming_activation, store_trace); + for (this._incoming in this.trace.influences[this._neuron.ID]) { + this._incoming_weight = this.getVar(this.trace.influences[this._neuron.ID][this._incoming], 'weight'); + this._incoming_activation = this.getVar(this.trace.influences[this._neuron.ID][this._incoming].from, 'activation'); + + if (this._initialized) + this.buildSentence(this._influence, ' += ', this._incoming_weight, ' * ', this._incoming_activation, this._store_trace); else { - buildSentence(influence, ' = ', incoming_weight, ' * ', incoming_activation, store_trace); - initialized = true; + this.buildSentence(this._influence, ' = ', this._incoming_weight, ' * ', this._incoming_activation, this._store_trace); + this._initialized = true; } } } @@ -527,237 +469,446 @@ export default class Neuron { for (var i in this.connections.inputs) { var input = this.connections.inputs[i]; if (input.gater) - var input_gain = getVar(input, 'gain'); - var input_activation = getVar(input.from, 'activation'); - var trace = getVar(this, 'trace', 'elegibility', input.ID, this.trace + var input_gain = this.getVar(input, 'gain'); + var input_activation = this.getVar(input.from, 'activation'); + var trace = this.getVar(this, 'trace', 'elegibility', input.ID, this.trace .elegibility[input.ID]); if (this.selfconnected()) { if (this.selfconnection.gater) { if (input.gater) - buildSentence(trace, ' = ', self_gain, ' * ', self_weight, + this.buildSentence(trace, ' = ', self_gain, ' * ', self_weight, ' * ', trace, ' + ', input_gain, ' * ', input_activation, - store_trace); + this._store_trace); else - buildSentence(trace, ' = ', self_gain, ' * ', self_weight, - ' * ', trace, ' + ', input_activation, store_trace); + this.buildSentence(trace, ' = ', self_gain, ' * ', self_weight, + ' * ', trace, ' + ', input_activation, this._store_trace); } else { if (input.gater) - buildSentence(trace, ' = ', self_weight, ' * ', trace, ' + ', - input_gain, ' * ', input_activation, store_trace); + this.buildSentence(trace, ' = ', self_weight, ' * ', trace, ' + ', + input_gain, ' * ', input_activation, this._store_trace); else - buildSentence(trace, ' = ', self_weight, ' * ', trace, ' + ', - input_activation, store_trace); + this.buildSentence(trace, ' = ', self_weight, ' * ', trace, ' + ', + input_activation, this._store_trace); } } else { if (input.gater) - buildSentence(trace, ' = ', input_gain, ' * ', input_activation, - store_trace); + this.buildSentence(trace, ' = ', input_gain, ' * ', input_activation, + this._store_trace); else - buildSentence(trace, ' = ', input_activation, store_trace); + this.buildSentence(trace, ' = ', input_activation, this._store_trace); } for (var id in this.trace.extended) { // extended elegibility trace var neuron = this.neighboors[id]; - var influence = getVar('influences[' + neuron.ID + ']'); + var influence = this.getVar('influences[' + neuron.ID + ']'); - var trace = getVar(this, 'trace', 'elegibility', input.ID, this.trace + var trace = this.getVar(this, 'trace', 'elegibility', input.ID, this.trace .elegibility[input.ID]); - var xtrace = getVar(this, 'trace', 'extended', neuron.ID, input.ID, + var xtrace = this.getVar(this, 'trace', 'extended', neuron.ID, input.ID, this.trace.extended[neuron.ID][input.ID]); if (neuron.selfconnected()) - var neuron_self_weight = getVar(neuron.selfconnection, 'weight'); + var neuron_self_weight = this.getVar(neuron.selfconnection, 'weight'); if (neuron.selfconnection.gater) - var neuron_self_gain = getVar(neuron.selfconnection, 'gain'); + var neuron_self_gain = this.getVar(neuron.selfconnection, 'gain'); if (neuron.selfconnected()) if (neuron.selfconnection.gater) - buildSentence(xtrace, ' = ', neuron_self_gain, ' * ', + this.buildSentence(xtrace, ' = ', neuron_self_gain, ' * ', neuron_self_weight, ' * ', xtrace, ' + ', derivative, ' * ', - trace, ' * ', influence, store_trace); + trace, ' * ', influence, this._store_trace); else - buildSentence(xtrace, ' = ', neuron_self_weight, ' * ', + this.buildSentence(xtrace, ' = ', neuron_self_weight, ' * ', xtrace, ' + ', derivative, ' * ', trace, ' * ', - influence, store_trace); + influence, this._store_trace); else - buildSentence(xtrace, ' = ', derivative, ' * ', trace, ' * ', - influence, store_trace); + this.buildSentence(xtrace, ' = ', derivative, ' * ', trace, ' * ', + influence, this._store_trace); } } for (var connection in this.connections.gated) { - var gated_gain = getVar(this.connections.gated[connection], 'gain'); - buildSentence(gated_gain, ' = ', activation, store_activation); + var gated_gain = this.getVar(this.connections.gated[connection], 'gain'); + this.buildSentence(gated_gain, ' = ', activation, this._store_activation); } } if (!isInput) { - var responsibility = getVar(this, 'error', 'responsibility', this.error + var responsibility = this.getVar(this, 'error', 'responsibility', this.error .responsibility); if (isOutput) { - var target = getVar('target'); - buildSentence(responsibility, ' = ', target, ' - ', activation, - store_propagation); + var target = this.getVar('target'); + this.buildSentence(responsibility, ' = ', target, ' - ', activation, + this._store_propagation); for (var id in this.connections.inputs) { var input = this.connections.inputs[id]; - var trace = getVar(this, 'trace', 'elegibility', input.ID, this.trace + var trace = this.getVar(this, 'trace', 'elegibility', input.ID, this.trace .elegibility[input.ID]); - var input_weight = getVar(input, 'weight'); - buildSentence(input_weight, ' += ', rate, ' * (', responsibility, - ' * ', trace, ')', store_propagation); + var input_weight = this.getVar(input, 'weight'); + this.buildSentence(input_weight, ' += ', rate, ' * (', responsibility, + ' * ', trace, ')', this._store_propagation); } - outputs.push(activation.id); + this._outputs.push(activation.id); } else { - if (!noProjections && !noGates) { - var error = getVar('aux'); - for (var id in this.connections.projected) { - var connection = this.connections.projected[id]; + if (!this._noProjections && !this._noGates) { + var error = this.getVar('aux'); + for (this._id in this.connections.projected) { + var connection = this.connections.projected[this._id]; var neuron = connection.to; - var connection_weight = getVar(connection, 'weight'); - var neuron_responsibility = getVar(neuron, 'error', - 'responsibility', neuron.error.responsibility); + var connection_weight = this.getVar(connection, 'weight'); + this._neuron_responsibility = this.getVar(neuron, 'error', 'responsibility', neuron.error.responsibility); if (connection.gater) { - var connection_gain = getVar(connection, 'gain'); - buildSentence(error, ' += ', neuron_responsibility, ' * ', - connection_gain, ' * ', connection_weight, - store_propagation); + var connection_gain = this.getVar(connection, 'gain'); + this.buildSentence( + error, + ' += ', + this._neuron_responsibility, + ' * ', + connection_gain, + ' * ', + connection_weight, + this._store_propagation + ); } else - buildSentence(error, ' += ', neuron_responsibility, ' * ', - connection_weight, store_propagation); + this.buildSentence( + error, + ' += ', + this._neuron_responsibility, + ' * ', + connection_weight, + this._store_propagation + ); } - var projected = getVar(this, 'error', 'projected', this.error.projected); - buildSentence(projected, ' = ', derivative, ' * ', error, - store_propagation); - buildSentence(error, ' = 0', store_propagation); - for (var id in this.trace.extended) { - var neuron = this.neighboors[id]; - var influence = getVar('aux_2'); - var neuron_old = getVar(neuron, 'old'); + var projected = this.getVar(this, 'error', 'projected', this.error.projected); + this.buildSentence(projected, ' = ', derivative, ' * ', error, + this._store_propagation); + this.buildSentence(error, ' = 0', this._store_propagation); + for (this._id in this.trace.extended) { + var neuron = this.neighboors[this._id]; + var influence = this.getVar('aux_2'); + var neuron_old = this.getVar(neuron, 'old'); if (neuron.selfconnection.gater == this) - buildSentence(influence, ' = ', neuron_old, store_propagation); + this.buildSentence(influence, ' = ', neuron_old, this._store_propagation); else - buildSentence(influence, ' = 0', store_propagation); + this.buildSentence(influence, ' = 0', this._store_propagation); for (var input in this.trace.influences[neuron.ID]) { var connection = this.trace.influences[neuron.ID][input]; - var connection_weight = getVar(connection, 'weight'); - var neuron_activation = getVar(connection.from, 'activation'); - buildSentence(influence, ' += ', connection_weight, ' * ', - neuron_activation, store_propagation); + var connection_weight = this.getVar(connection, 'weight'); + var neuron_activation = this.getVar(connection.from, 'activation'); + this.buildSentence(influence, ' += ', connection_weight, ' * ', + neuron_activation, this._store_propagation); } - var neuron_responsibility = getVar(neuron, 'error', - 'responsibility', neuron.error.responsibility); - buildSentence(error, ' += ', neuron_responsibility, ' * ', - influence, store_propagation); + this._neuron_responsibility = this.getVar( + neuron, + 'error', + 'responsibility', + neuron.error.responsibility + ); + this.buildSentence( + error, + ' += ', + this._neuron_responsibility, + ' * ', + influence, + this._store_propagation + ); } - var gated = getVar(this, 'error', 'gated', this.error.gated); - buildSentence(gated, ' = ', derivative, ' * ', error, - store_propagation); - buildSentence(responsibility, ' = ', projected, ' + ', gated, - store_propagation); - for (var id in this.connections.inputs) { - var input = this.connections.inputs[id]; - var gradient = getVar('aux'); - var trace = getVar(this, 'trace', 'elegibility', input.ID, this - .trace.elegibility[input.ID]); - buildSentence(gradient, ' = ', projected, ' * ', trace, - store_propagation); - for (var id in this.trace.extended) { - var neuron = this.neighboors[id]; - var neuron_responsibility = getVar(neuron, 'error', - 'responsibility', neuron.error.responsibility); - var xtrace = getVar(this, 'trace', 'extended', neuron.ID, - input.ID, this.trace.extended[neuron.ID][input.ID]); - buildSentence(gradient, ' += ', neuron_responsibility, ' * ', - xtrace, store_propagation); + this._gated = this.getVar(this, 'error', 'gated', this.error.gated); + this.buildSentence( + this._gated, + ' = ', + derivative, + ' * ', + error, + this._store_propagation + ); + this.buildSentence( + responsibility, + ' = ', + projected, + ' + ', + this._gated, + this._store_propagation + ); + for (this._id in this.connections.inputs) { + this._input = this.connections.inputs[this._id]; + var gradient = this.getVar('aux'); + var trace = this.getVar( + this, + 'trace', + 'elegibility', + this._input.ID, + this.trace.elegibility[this._input.ID] + ); + this.buildSentence( + gradient, + ' = ', + projected, + ' * ', + trace, + this._store_propagation + ); + for (this._id in this.trace.extended) { + var neuron = this.neighboors[this._id]; + var neuron_responsibility = this.getVar( + neuron, + 'error', + 'responsibility', + neuron.error.responsibility + ); + var xtrace = this.getVar( + this, + 'trace', + 'extended', + neuron.ID, + this._input.ID, + this.trace.extended[neuron.ID][this._input.ID] + ); + this.buildSentence( + gradient, + ' += ', + neuron_responsibility, + ' * ', + xtrace, + this._store_propagation + ); } - var input_weight = getVar(input, 'weight'); - buildSentence(input_weight, ' += ', rate, ' * ', gradient, - store_propagation); + this._input_weight = this.getVar(this._input, 'weight'); + this.buildSentence( + this._input_weight, + ' += ', + rate, + ' * ', + gradient, + this._store_propagation + ); } - } else if (noGates) { - buildSentence(responsibility, ' = 0', store_propagation); - for (var id in this.connections.projected) { - var connection = this.connections.projected[id]; - var neuron = connection.to; - var connection_weight = getVar(connection, 'weight'); - var neuron_responsibility = getVar(neuron, 'error', - 'responsibility', neuron.error.responsibility); - if (connection.gater) { - var connection_gain = getVar(connection, 'gain'); - buildSentence(responsibility, ' += ', neuron_responsibility, - ' * ', connection_gain, ' * ', connection_weight, - store_propagation); + } else if (this._noGates) { + this.buildSentence(responsibility, ' = 0', this._store_propagation); + for (this._id in this.connections.projected) { + this._connection = this.connections.projected[this._id]; + var neuron = this._connection.to; + var connection_weight = this.getVar(this._connection, 'weight'); + var neuron_responsibility = this.getVar(neuron, 'error', 'responsibility', neuron.error.responsibility); + + if (this._connection.gater) { + var connection_gain = this.getVar(this._connection, 'gain'); + this.buildSentence( + responsibility, + ' += ', + neuron_responsibility, + ' * ', + connection_gain, + ' * ', + connection_weight, + this._store_propagation + ); } else - buildSentence(responsibility, ' += ', neuron_responsibility, - ' * ', connection_weight, store_propagation); + this.buildSentence( + responsibility, + ' += ', + neuron_responsibility, + ' * ', + connection_weight, + this._store_propagation + ); } - buildSentence(responsibility, ' *= ', derivative, - store_propagation); - for (var id in this.connections.inputs) { - var input = this.connections.inputs[id]; - var trace = getVar(this, 'trace', 'elegibility', input.ID, this - .trace.elegibility[input.ID]); - var input_weight = getVar(input, 'weight'); - buildSentence(input_weight, ' += ', rate, ' * (', - responsibility, ' * ', trace, ')', store_propagation); + + this.buildSentence(responsibility, ' *= ', derivative,this._store_propagation); + + for (this._id in this.connections.inputs) { + this._input = this.connections.inputs[this._id]; + this._trace = this.getVar( + this, + 'trace', + 'elegibility', + this._input.ID, + this.trace.elegibility[this._input.ID] + ); + this._input_weight = this.getVar(this._input, 'weight'); + this.buildSentence( + this._input_weight, + ' += ', + rate, + ' * (', + responsibility, + ' * ', + this._trace, ')', + this._store_propagation + ); } - } else if (noProjections) { - buildSentence(responsibility, ' = 0', store_propagation); - for (var id in this.trace.extended) { - var neuron = this.neighboors[id]; - var influence = getVar('aux'); - var neuron_old = getVar(neuron, 'old'); + } else if (this._noProjections) { + this.buildSentence(responsibility, ' = 0', this._store_propagation); + + for (this._id in this.trace.extended) { + var neuron = this.neighboors[this._id]; + var influence = this.getVar('aux'); + var neuron_old = this.getVar(neuron, 'old'); if (neuron.selfconnection.gater == this) - buildSentence(influence, ' = ', neuron_old, store_propagation); + this.buildSentence(influence, ' = ', neuron_old, this._store_propagation); else - buildSentence(influence, ' = 0', store_propagation); - for (var input in this.trace.influences[neuron.ID]) { - var connection = this.trace.influences[neuron.ID][input]; - var connection_weight = getVar(connection, 'weight'); - var neuron_activation = getVar(connection.from, 'activation'); - buildSentence(influence, ' += ', connection_weight, ' * ', - neuron_activation, store_propagation); + this.buildSentence(influence, ' = 0', this._store_propagation); + for (this._input in this.trace.influences[neuron.ID]) { + this._connection = this.trace.influences[neuron.ID][this._input]; + var connection_weight = this.getVar(this._connection, 'weight'); + var neuron_activation = this.getVar(this._connection.from, 'activation'); + this.buildSentence(influence, ' += ', connection_weight, ' * ', + neuron_activation, this._store_propagation); } - var neuron_responsibility = getVar(neuron, 'error', - 'responsibility', neuron.error.responsibility); - buildSentence(responsibility, ' += ', neuron_responsibility, - ' * ', influence, store_propagation); + this._neuron_responsibility = this.getVar(neuron, 'error', 'responsibility', neuron.error.responsibility); + this.buildSentence( + responsibility, + ' += ', + this._neuron_responsibility, + ' * ', + influence, + this._store_propagation + ); } - buildSentence(responsibility, ' *= ', derivative, - store_propagation); - for (var id in this.connections.inputs) { - var input = this.connections.inputs[id]; - var gradient = getVar('aux'); - buildSentence(gradient, ' = 0', store_propagation); - for (var id in this.trace.extended) { - var neuron = this.neighboors[id]; - var neuron_responsibility = getVar(neuron, 'error', - 'responsibility', neuron.error.responsibility); - var xtrace = getVar(this, 'trace', 'extended', neuron.ID, - input.ID, this.trace.extended[neuron.ID][input.ID]); - buildSentence(gradient, ' += ', neuron_responsibility, ' * ', - xtrace, store_propagation); + this.buildSentence(responsibility, ' *= ', derivative, this._store_propagation); + + for (this._i in this.connections.inputs) { + this._input = this.connections.inputs[this._i]; + this._gradient = this.getVar('aux'); + this.buildSentence(this._gradient, ' = 0', this._store_propagation); + for (this._id in this.trace.extended) { + this._neuron = this.neighboors[this._id]; + this._neuron_responsibility = this.getVar( + this._neuron, + 'error', + 'responsibility', + this._neuron.error.responsibility + ); + this._xtrace = this.getVar( + this, + 'trace', + 'extended', + this._neuron.ID, + this._input.ID, + this.trace.extended[this._neuron.ID][this._input.ID] + ); + this.buildSentence( + this._gradient, + ' += ', + this._neuron_responsibility, + ' * ', + this._xtrace, + this._store_propagation + ); } - var input_weight = getVar(input, 'weight'); - buildSentence(input_weight, ' += ', rate, ' * ', gradient, - store_propagation); + this._input_weight = this.getVar(this._input, 'weight'); + + this.buildSentence( + this._input_weight, + ' += ', + rate, + ' * ', + this._gradient, + this._store_propagation + ); } } } - buildSentence(bias, ' += ', rate, ' * ', responsibility, - store_propagation); + this.buildSentence(bias, ' += ', rate, ' * ', responsibility, + this._store_propagation); } + return { - memory: varID, + memory: this._varID, + inputs: this._inputs, + layers: this._layers, neurons: neurons + 1, - inputs: inputs, - outputs: outputs, - targets: targets, - variables: variables, - activation_sentences: activation_sentences, - trace_sentences: trace_sentences, - propagation_sentences: propagation_sentences, - layers: layers + outputs: this._outputs, + targets: this._targets, + variables: this._variables, + trace_sentences: this._trace_sentences, + activation_sentences: this._activation_sentences, + propagation_sentences: this._propagation_sentences, } } + // build sentence + buildSentence() { + this._args = Array.prototype.slice.call(arguments); + this._store = this._args.pop(); + this._sentence = ''; + for (this._i = 0; this._i < this._args.length; this._i++) { + if (typeof this._args[this._i] == 'string') + this._sentence += this._args[this._i]; + else + this._sentence += 'F[' + this._args[this._i].id + ']'; + } + + this._store.push(this._sentence + ';'); + } + + // allocate sentences + allocate(layer, store) { + this._allocated = layer in this._layers && store[this._layers.__count]; + if (!this._allocated) { + this._layers.__count = store.push([]) - 1; + this._layers[layer] = this._layers.__count; + } + } + + // get/reserve space in memory by creating a unique ID for a variablel + getVar() { + this._args = Array.prototype.slice.call(arguments); + + if (this._args.length == 1) { + this._id = ''; + + if (this._args[0] == 'target') { + this._id = `target_${this._targets.length}`; + this._targets.push(this._varID); + } else + this._id = this._args[0]; + + if (this._id in this._variables) + + return this._variables[this._id]; + else + + return this._variables[this._id] = { + value: 0, + id: this._varID++ + }; + + } else { + this._extended = this._args.length > 2; + if (this._extended) + this._value = this._args.pop(); + + this._unit = this._args.shift(); + this._prop = this._args.pop(); + + if (!this._extended) + this._value = this._unit[this._prop]; + + this._id = `${this._prop}_`; + + for (this._i in this._args) + this._id += `${this._args[this._i]}_`; + + this._id += this._unit.ID; + + if (this._id in this._variables) + return this._variables[this._id]; + else + return this._variables[this._id] = { + value: this._value, + id: this._varID++ + }; + } + } + + // helper to check if an object is empty + isEmpty(obj) { + for (this._i in obj) { + if (obj.hasOwnProperty(this._i)) + return false; + } + + return true; + } + static uid() { return neurons++; }